Java 将自引用实体休眠为非空列
我正在使用Hibernate5和Spring3.2.4。我正在设计一个用户实体,我想在其中包含一个对创建该实体的用户的引用,也就是一个自引用。自引用本身没有太大问题,但我想将字段指定为非null。这可能吗?如果字段为非null,因为引用的实体不存在,那么如何在DB中创建第一个条目 例: 如果我尝试:Java 将自引用实体休眠为非空列,java,hibernate,jpa,persistence,hibernate-5.x,Java,Hibernate,Jpa,Persistence,Hibernate 5.x,我正在使用Hibernate5和Spring3.2.4。我正在设计一个用户实体,我想在其中包含一个对创建该实体的用户的引用,也就是一个自引用。自引用本身没有太大问题,但我想将字段指定为非null。这可能吗?如果字段为非null,因为引用的实体不存在,那么如何在DB中创建第一个条目 例: 如果我尝试: User u = new User(); u.setUsername("username"); u.setCreatedBy(u); 并尝试保持u,我会收到以下错误消息: Caused by: o
User u = new User();
u.setUsername("username");
u.setCreatedBy(u);
并尝试保持u
,我会收到以下错误消息:
Caused by: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.domain.User.createdBy -> com.domain.User
我知道Hibernate正在抱怨它不能引用一个临时实例(即:u
),但是我不能持久化u
,除非我可以引用一个非空用户。但是在空数据库中,没有这样的条目
这种配置是不可能的吗?或者有办法解决这个问题吗?由于注释
@NOTNULL
,由u
创建的字段不能为空。但是u
指的是它自己,它在保存之前不会持久存在。
您可以为u
设置另一个持久化的用户,而不是它本身。我不理解这个Roo注释,也不使用特定于Hibernate的注释,只使用JPA。我对自我介绍没有任何问题。但我有一些提示:
如前所述,使用@ManyToOne
注释
好的,@NotNull
注释(或@Column
中的null
字段)不影响映射,只影响DDL生成。我不使用从域模型生成DDL,我从不指定这一点。相反,我使用了@ManyToOne
的可选字段
您使用什么标识符生成策略?如果自动递增,则不可能使用NOT NULL
约束进行自引用。所以,要么使用基于序列的标识符生成器,要么删除约束。我会先用
正如我提到的,当您有非空
约束时,将@ManyToOne
的可选
字段设置为假
。否则,Hibernate会尝试进行两次查询:将createdBy_id
设置为NULL
时插入,然后更新createdBy_id
。第一个查询在启用了非NULL
约束的情况下失败
我找到了解决办法。必须为ID使用序列生成器(而不是默认的自动生成ID)。然后它就起作用了
@Entity
public class UserModel {
/**
* We must use a sequence for generating IDs,
* because of the self reference .
* https://vladmihalcea.com/2014/07/15/from-jpa-to-hibernates-legacy-and-enhanced-identifier-generators/
*/
@Id
@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)
@SequenceGenerator(name = "sequence", allocationSize = 10)
private Long id;
/** reference to a parent user, e.g. the manager */
@ManyToOne(optional = false)
@NotNull
UserModel parentUser;
[...]
原因如下:当Hibernate尝试插入新用户时,它还尝试验证对parentUser的引用。但对于我们要插入的第一个用户,这将失败,或者当用户引用自己时,也将失败
但是,当使用序列生成ID时,新的/下一个ID在插入时就已经知道了。您是否尝试过使用@ManyToOne指定映射?此外,我没有看到标识符字段,您是否像setters一样省略了它?@难以捉摸的代码-我在没有@Roo
注释的情况下更新了实体以显示其他文件。是的,为了简洁起见,我省略了getter/setter。根据我的理解,@ManyToOne和@NotNull之间的区别在于,@ManyToOne将用于DDL生成和持久化bean时,然而@NotNull可以用于bean验证,即使在不持久化bean时也是如此。自动增量主键生成的假设是正确的。但当使用基于序列的PK生成器时,ID在插入之前就已经知道了。因此,执行有效的INSERT
查询确实是可能的。正如我在最初的帖子中所说,我知道这就是问题的根源。但是问题仍然存在——如何创建表中的第一行?没有其他用户可以分配它。我已经编辑了实体,以提供没有@Roo
注释的示例。是-我正在为此表使用autoincrement,没有考虑使用其他GUID策略。我将尝试使用基于序列的标识符。然而,据我所知,Hibernate注释和@NotNull
之间的区别在于前者将确保DB模式设置,而后者将用于bean验证,即使不会持久化到DB。我通过自动生成更改为表生成(MySQL不支持序列)。现在看来一切如愿。谢谢
@Entity
public class UserModel {
/**
* We must use a sequence for generating IDs,
* because of the self reference .
* https://vladmihalcea.com/2014/07/15/from-jpa-to-hibernates-legacy-and-enhanced-identifier-generators/
*/
@Id
@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)
@SequenceGenerator(name = "sequence", allocationSize = 10)
private Long id;
/** reference to a parent user, e.g. the manager */
@ManyToOne(optional = false)
@NotNull
UserModel parentUser;
[...]