Hibernate自引用实体为非空列

时间:2013-11-29 04:07:31

标签: java hibernate jpa persistence hibernate-5.x

我正在使用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中,没有这样的条目。

这种配置不可能吗?或者有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

我不理解这个Roo注释,我不使用特定于Hibernate的注释,只使用JPA。我对自引用没有任何问题。但是我有一些提示:

  1. 如前所述,请使用@ManyToOne注释。
  2. AFAIK,@NotNull注释(或nullable中的@Column字段)不会影响映射,只影响DDL生成。我不使用域模型生成DDL,我从不指定它。相反,我使用optional的{​​{1}}字段。
  3. 您使用什么标识符生成策略?如果自动增量,则@ManyToOne约束不可能进行自引用。因此要么使用基于序列的标识符生成器要么删除约束。我先用。
  4. 正如我所提到的,当NOT NULL约束时,请将optional的{​​{1}}字段设置为@ManyToOne。否则,Hibernate会尝试进行两次查询:将false设置为NOT NULL,然后更新createdBy_id。第一个查询失败并启用了NULL约束。

答案 1 :(得分:0)

由于注释createdByu的字段@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。