我正在使用Hibernate 5和Spring 3.2.4。我正在设计一个User实体,我希望在其中包含对创建实体的用户的引用 - 所以我自己引用。自引用本身不是太有问题,但我想将该字段指定为非null。这可能吗?如果字段为非null,如何在数据库中创建第一个条目,因为引用的实体尚不存在?
例如:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long User.id;
@NotNull
private String username;
private String password;
@NotNull
private User user;
// getters and setters omitted for brevity
}
如果我尝试:
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
,除非我有一个非空用户,我可以参考。但是在一个空的DB中,没有这样的条目。
这种配置不可能吗?或者有办法解决这个问题吗?
答案 0 :(得分:3)
我不理解这个Roo注释,我不使用特定于Hibernate的注释,只使用JPA。我对自引用没有任何问题。但是我有一些提示:
@ManyToOne
注释。@NotNull
注释(或nullable
中的@Column
字段)不会影响映射,只影响DDL生成。我不使用域模型生成DDL,我从不指定它。相反,我使用optional
的{{1}}字段。@ManyToOne
约束不可能进行自引用。因此要么使用基于序列的标识符生成器要么删除约束。我先用。NOT NULL
约束时,请将optional
的{{1}}字段设置为@ManyToOne
。否则,Hibernate会尝试进行两次查询:将false
设置为NOT NULL
,然后更新createdBy_id
。第一个查询失败并启用了NULL
约束。答案 1 :(得分:0)
由于注释createdBy
,u
的字段@NOTNULL
不能为空。但是u
对自己有所启示,并且在保存它之前它不会持续存在。
您可以为User
设置另一个持久u
,而不是其自身。
答案 2 :(得分:0)
我找到了解决方案。您必须为您的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。