【问题标题】:Hibernate zeroToOne休眠零到一
【发布时间】:2010-08-17 13:41:10
【问题描述】:

我正在尝试在 2 个实体之间建立零对一的关系。也就是说,Parent 可以在没有关联的 Child 实体的情况下保存,也可以与关联的 Child 一起保存。 以下是 2 个实体类...


员工(父母)

public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name="EMP_NAME")
    private String name;

    @PrimaryKeyJoinColumn
    @OneToOne(cascade = {CascadeType.ALL})
    private EmployeeInfo info;

    @Column(name="EMP_ENUM")
    private Integer enumId;

员工信息(儿童)

public class EmployeeInfo {
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;

        @Column(name="EMPLOYEE_EMAIL")
        private String email;

在 MySql DB 中,唯一的 Parent (Employee) 表的这种关系和 id 列设置为 AUTO INCREMENT,问题是在保存 Parent->Child 对象图时,我得到以下异常

org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [insert into EMP_INFO 
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value

我尝试在DB中将Child Table的Id属性设置为AUTO INCREMENT,这样的Parent->Child对象图的持久化是成功的。 但是,问题描述了here 表面,因为我有一个场景,我想在没有关联 EmpInfo 对象的情况下保存父(员工)对象,并且 因此不想在孩子的 id 上使用 AUTO INCREMENT列


一种解决方案可能是不使用 PrimaryKeyJoinColumn,而是使用特定的 JoinColumn,但这会在我现有的表中添加一个不必要的列。


有人遇到过这样的问题吗?如果是,任何指针都会很有帮助。

【问题讨论】:

    标签: java hibernate orm jpa shared-primary-key


    【解决方案1】:

    最后,多亏了 Pascal 和我的一些谷歌搜索,我才让它工作起来。显然,我不能将本机密钥生成器用于这样的关系,其中父项可以在没有子项的情况下存在(可选 = true)。 最终起作用的是以下内容,这让我不得不处理 Hibernate 特定注释 (@GenericGenerator) 并且还必须使用双向关系而不是我想要的单向关系。

    Employee (Parent) class remains unchanged as above. It has AUTO INCREMENT on the Id column.
    

    至于子类 (EmployeeInfo),它更改为以下内容,并且再次 WITHOUT 在 Id 列上设置了 AUTO INCREMENT。

    @Table(name="EMP_INFO")
    @Entity
    public class EmployeeInfo {
        @Id
        @GeneratedValue(generator="foreign")
        @GenericGenerator(name="foreign", strategy = "foreign", parameters={
        @Parameter(name="property", value="verifInfo")}) 
        private Long id;
    
        @OneToOne(optional=false)
        @JoinColumn (name="id")
        private Employee emp;
    
        @Column(name="EMPLOYEE_EMAIL")
        private String email;
    

    这帮助我实现了我想要的,但不利的一面是,GenericGenerator 不是 JPA 注释,它是一个休眠注释,遗憾的是我现在不得不这样做,因为 JPA 目前不支持这个(或任何类似)注释。

    无论如何,这有助于解决这种情况:-)

    【讨论】:

      【解决方案2】:

      我有一个场景,我想在没有关联 EmpInfo 对象的情况下保存父(员工)对象。

      OneToOneoptional 属性默认为true,这是您想要的。

      但是,您在这里以某种方式滥用了@PrimaryKeyJoinColumn(嗯,这实际上取决于您真正想要实现的目标,但您当前的注释组合不正确)。

      如果您想用共享主键映射OneToOne,请使用@PrimaryKeyJoinColumn。但在这种情况下,不要在 EmployeeInfo 上使用 GeneratedValue 并手动设置 id,或者,如果您不想手动设置,请使用 Hibernate specific foreign 生成器我已经在your previous question 中提到过。还要检查下面提到的相关问题。

      并且如果您不想使用共享主键(就像在您当前的代码中,因为您试图获取数据库生成的 id),那么 不要使用PrimaryKeyJoinColumn

      你必须做出选择。

      参考文献

      • JPA 1.0 规范:
        • 9.1.32 PrimaryKeyJoinColumn注解

      相关问题

      【讨论】:

      • 嘿帕斯卡,感谢您一如既往的回复 :) 至于您的建议“不要在 EmployeeInfo 上使用 GeneratedValue 并手动设置” - 问题是在保存父级(员工)之前我不会有与之关联的 id,因此我不能手动将其传递给子对象。至于“使用 Hibernate 特定的外部生成器”,我已经尝试过了,但它给了我一个 NPE(我将粘贴堆栈跟踪以及我明天再次接触代码时所做的事情)。顺便说一句,是什么让您认为我不想使用共享主键?事实上,我想要那个!
      • 继续我之前的评论.. 我想使用共享主键,我的代码中有什么让你觉得我不想要它?但是,对于共享主键连接列,我还希望满足 2 个场景 i) 单独保存的父 ii) 保存的父和子 - 在这种情况下,共享主键实际上会出现。我希望这能让问题更清楚。
      • 另外,是的,感谢您指出我以前的帖子。这是我计划的较早方法(即通过手动设置父实体的 ID 来单独保存子实体)。我现在更改了方法,通过保存整个对象图(从父级 -> 子级,即使在我希望单独保存子级的情况下),使其不易出错。
      • @PaiS: Btw, what makes you think that I do not want to use a shared primary key? 因为我们昨天看到,如果不使用特定的 foreign 生成器,这将无法与 @GeneratedValue 一起使用,这就是您在这个问题中尝试做的事情:)
      • @PaiS: However, with the shared primary key join column, I also want 2 scenarios to be satisfied i) The parent saved alone ii) Parent along with the child saved 我看不出问题,应该可以有一个null 孩子。随时使用准确的映射和堆栈跟踪更新问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      • 2016-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多