在用户名或用户电子邮件等属性下添加@Id注释是否是一种好的做法



>例如,当您为 id 以外的文件设置@Id属性时可能发生哪些复杂情况

@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="user_id")
private Integer user_id;
@Id
@Size(min=6,message="email is too short")
@Pattern(regexp = "^.+@.+\..+$",message="invalid email")
@Column(name="user_email")
private String user_email;

在我的用户 pojo 类中:如果我不是为user_id定义 id 注释,而是为user_email从长远来看,这会产生任何复杂性吗?

这是不好的做法。

电子邮件可能会更改,但主键(这是@Id注释的内容(不应更改。用户名也可能更改,例如在此站点上。

首先让我说:这是一个很好的问题!简短的回答是:

不,使用@Id注释user_emailusername等字段不是一个好的做法。

为了更深入地了解为什么,让我们首先记住主键 (PK( 是如何定义的。在大多数面向 SQL 的数据库系统中,PK 定义至少遵循两个假设,在这些假设下,PK 始终是:

  • (i( 不为空
  • (二( 独特

关于您的想法/问题的含义:

  • (一(:

    usernameuser_email值必须设置为User实例,然后才能将其保存到数据库。在这种情况下,它丢失或仅在以后的时间点才知道:持久性=不可能。反之亦然,它永远不能设置为未知值,也就是null,例如,如果用户根本无法提供他/她的电子邮件地址(即使在 2018 年这种情况很少见(。

  • (二(:

    username/user_email的实际值在大多数应用中往往是唯一的。但是,在应用程序的业务逻辑中,您必须确保没有其他用户输入已经存在/已知的username/user_email两次。如果你@Id注释,再一次:持久性=不可能。尽管如此,最有可能的是,允许其中一个字段重复会以任何方式违反其语义。

如果您将user_id注释为@Id字段:两种情况下都没有痛苦。

在ORM上下文中,JPA规范文档扩展了此定义,并在第31页上指出:

其主键的值唯一标识持久性上下文中的实体实例,并 第 3 章 "实体操作"中所述的实体管理器操作。应用程序不得更改主键的值。如果发生这种情况,则行为未定义。

这产生了下一个含义

  • (三(

    根据定义,不允许以编程方式/在运行时更改@Id字段的值。此类字段的控制应完全保留在实现 JPA 规范的对象关系映射器方面。

正如Bohemian在回答中指出的那样,usernameuser_email可能会在应用程序的生命周期内发生变化。原因是:从应用程序用户的角度来看,数据是流动的。用户可能希望更改这些属性(在将来的某个时间(,例如,如果他们结婚或更改其电子邮件提供商。

尽管如此,通常可以注释类型String(和其他字段(的字段,见第31页:

简单主键或

复合主键的字段或属性应为以下类型之一:任意Java primitive type; 任何基元包装器类型;java.lang.String;java.util.Date;java.sql.Date;java.math.BigDecimal;java.math.BigInteger.

所以人们可能会受到诱惑并说:好吧,让我们继续吧!但是,应该退后一步,反映 (a( 域或 (b( 应用程序的预期用例对预期应用程序的数据库模式施加什么。如上所述,这在你的方案中尤其重要。

考虑到这些"现实世界"的注意事项,您最好只将@Id注释为代理键,例如示例中的user_id。在数据库的整个生存期内,此值不会更改。问题:为什么它不会改变?答:没有实际的理由来满足应用程序用户定义的业务案例。

希望这有帮助。

°提示

最好从一开始就使用Long而不是Integer;因此,您将拥有足够的主键值,远远超过您作为软件开发人员的生命周期(对于>99.5%的应用程序都是如此(。

相关内容

最新更新