【问题标题】:JPA 2.0 - Persist child entity automatically on Parent persist, giving org.hibernate.id.IdentifierGenerationExceptionJPA 2.0 - 在 Parent 上自动持久化子实体,给 org.hibernate.id.IdentifierGenerationException
【发布时间】:2015-03-07 00:06:16
【问题描述】:

我有两个名为 Customer 和他的 Biiling Address 的实体。关系是一对一的。每个客户都有一个账单地址。 我想在保留客户时自动保留帐单地址。 客户 id 是客户实体的主键,也是地址实体的主键和外键。

//parent table
public class CustomerDTO implements Serializable {

@Id
@GeneratedValue
@Column(name = "customer_id")
private Integer id;

@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL )
@PrimaryKeyJoinColumn(name="customer_id")
BillingAddressDTO billingAddressDTO;



//child table
public class BillingAddressDTO implements Serializable {
@Id
@Column(name="customer_id")
private Integer id;

这是我用来持久化实体的代码

    customerDTO = new CustomerDTO();
    customerDTO.setFirstName(firstName);

    billingAddressDTO = new BillingAddressDTO();
    billingAddressDTO.setBillingAddress(address1);
    customerDTO.setBillingAddressDTO(billingAddressDTO);
   //persisting customer entity
   customerDAO.persist(customerDTO);

我收到以下异常

  Caused by: org.hibernate.id.IdentifierGenerationException: ids for this   
  class must be manually assigned before calling save():

我想将相同的客户 ID 分配给地址表,所以我不想手动分配它。感谢您的宝贵时间。

【问题讨论】:

    标签: hibernate jpa-2.0


    【解决方案1】:

    您需要的是所谓的派生标识符。在这种方法中,CustomerDTO(父实体)的主键与BillingAddressDTO(从属实体)共享。

    @Entity
    public class CustomerDTO implements Serializable {
        @Id
        @GeneratedValue
        @Column(name = "customer_id")
        private Integer id;
    
        @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        @PrimaryKeyJoinColumn(name = "customer_id")
        private BillingAddressDTO billingAddressDTO;
        ...
    }
    
    @Entity
    public class BillingAddressDTO implements Serializable {
        @Id
        private Integer id; // @Column is NOT allowed since id is indicated by @MapsId
    
        @MapsId
        @OneToOne(mappedBy = "billingAddressDTO")
        @JoinColumn(name = "customer_id")
        private CustomerDTO customerDTO;
        ...
    }
    

    在上述场景中,父实体CustomerDTO 有一个简单的主键customer_id,而从属实体BillingAddressDTO 共享一个由关系属性customerDTO 映射的主键属性。


    更新:基于阿里评论的替代解决方案,以避免双向关系

    @Entity
    public class CustomerDTO implements Serializable {
        @Id
        private Integer id;
    
        @MapsId
        @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        @JoinColumn(name = "customer_id")
        private BillingAddressDTO billingAddressDTO;
        ...
    }
    
    @Entity
    public class BillingAddressDTO implements Serializable {
        @Id
        @GeneratedValue
        @Column(name = "customer_id")
        private Integer id;
        ...
    }
    

    在上述场景中,父实体BillingAddressDTO 有一个简单的主键customer_id,而从属实体CustomerDTO 共享一个由关系属性billingAddressDTO 映射的主键属性。


    从底层数据库的角度来看,实体如下所示:

    customer_id  firstname
    -----------  ---------
              1  Ali Baba
    
    customer_id  billingaddress
    -----------  --------------
              1  my_address
    

    参考资料:

    • JPA 2.0 规范,第 2.4.1 章:对应于派生身份的主键

    【讨论】:

    • 谢谢@wypieprz。它对我有用,但我有一个问题,如果我在这里犯了概念上的错误,请纠正我。将客户(父实体)放在地址(子实体)中是否违反逻辑。我认为这样,关系是双向的,但我们不需要将客户放在地址中,因为每当我需要地址时,我都可以从客户那里得到它。
    • 我不会称之为错误,但实际上它可能在概念上不适合您的需求。我已经更新了我的答案以避免双向关系,因此您可以从客户那里获取地址,而地址本身不知道它属于谁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 2017-10-21
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    相关资源
    最近更新 更多