例如,为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注释,从长远来看会不会带来任何麻烦?
答案 0 :(得分:0)
这是不好的做法。
电子邮件可能会更改,但是主键(@Id
所注释的内容)永远不会更改。用户名也可能会更改,例如在此站点上。
答案 1 :(得分:0)
首先让我说:这是一个好问题!简短的答案是:
否,用
user_email
注释username
或@Id
之类的字段不是一个好习惯。
要深入了解为什么,让我们首先记住如何定义主键(PK)。在大多数面向SQL的数据库系统中,PK definition至少遵循两个假设,PK始终为:
与您的想法/问题有关的含义:
(a):
在将username
或user_email
值持久保存到数据库之前,必须将其设置为User
实例。在这种情况下,它不存在或仅在以后的某个时间才知道:持久性=不可能。反之亦然,例如,如果用户根本无法提供他/她的电子邮件地址(即使在2018年很少见),则永远不能将其设置为 unknown 值,也称为null
。
(b):
username
/ user_email
的实际值在大多数应用程序中往往是唯一的。但是,您必须确保在应用程序的业务逻辑中,没有其他用户两次输入已经存在/已知的username
/ user_email
。再次给您添加@Id
注释:持久性=不可能。不过,很可能在这些字段之一中允许重复项将以任何方式违反其语义。
如果您将user_id
注释为@Id
字段:两种情况都没有痛苦。
在ORM上下文中,the JPA specification document扩展此定义并在第31页上指出:
其主键的值唯一标识持久性上下文中的实体实例,并 如第3章“实体操作”中所述的EntityManager操作。应用程序不得更改主键的值。如果发生这种情况,则该行为是不确定的。
这产生了下一个含义
(c)
根据定义,您不允许以编程方式/在运行时更改字段的@Id
值。此类字段的控制应完全保留在实现JPA规范的对象关系映射器的一侧。
正如 Bohemian 的回答所指出的,username
或user_email
可能会在应用程序的生命周期内发生变化。原因:从应用程序用户的角度来看,数据是不稳定的。用户可能想更改这些属性(在将来的某个时间),例如,如果他们结婚或更改电子邮件提供商。
尽管如此,通常可以注释类型String
(及其他)的字段,请参见p。 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
;因此,您将拥有足够的主键值,远远超过了作为SW开发人员的寿命(对于所有应用程序来说> 99.5%都是正确的)。