【问题标题】:Hibernate/JPA not able to set the parent's id to child's candidate keyHibernate/JPA 无法将父级的 id 设置为子级的候选键
【发布时间】:2020-05-20 19:43:43
【问题描述】:

代码示例如下:

家长:

@Table(name="PURCHASE_ORDER")
public class PurchaseOrder implements Serializable {

   private static final long serialVersionUID = 2006292307678909083L;

   @Id
   @SequenceGenerator(name="PURCHASE_ORDER_ID_GENERATOR", sequenceName="PURCHASE_ORDER_SEQ", allocationSize = 1)
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PURCHASE_ORDER_ID_GENERATOR")
   @Column(name="PURCHASE_ORDER_ID")
   private BigDecimal id;

   // more fields... 

   @JsonManagedReference
   @OneToMany(fetch = FetchType.LAZY, mappedBy="purchaseOrderByDetail", cascade = CascadeType.ALL)
   private List<PurchaseOrderDetail> purchaseOrderDetails;

}

PurchaseOrder 的孩子和PurchaseOrderCost 的父母:

@Entity
@Table(name="PURCHASE_ORDER_DETAIL")
public class PurchaseOrderDetail implements Serializable {

    @Id
    @SequenceGenerator(name="PURCHASE_ORDER_DETAIL_ID_GENERATOR", sequenceName="PURCHASE_ORDER_DETAIL_SEQ", allocationSize = 1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PURCHASE_ORDER_DETAIL_ID_GENERATOR")
    @Column(name="PURCHASE_ORDER_DETAIL_ID")
    private BigDecimal id;

    @Column(name="CANCEL_DATE")
    private Date cancelDate;

    @JsonBackReference
    @ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name="PURCHASE_ORDER_ID")
    private PurchaseOrder purchaseOrderByDetail;

    @JsonManagedReference
    @OneToMany(fetch=FetchType.LAZY, mappedBy="purchaseOrderDetailByCost", cascade = CascadeType.ALL)
    private List<PurchaseOrderCost> purchaseOrderCosts;

}

孩子到PurchaseOrderDetail:

@Entity
@Table(name="PURCHASE_ORDER_COST")
public class PurchaseOrderCost implements Serializable {

    @EmbeddedId
    private PurchaseOrderCostPK id;

    //.. other fields..
}

复合键PurchaseOrderCostPK 详情:

@Embeddable
public class PurchaseOrderCostPK implements Serializable {

    @Column(name="COST_TYPE_ID")
    private BigDecimal costTypeId;

    @Column(name="PURCHASE_ORDER_DETAIL_ID")
    private BigDecimal purchaseOrderDetailId;

    //.. overridden equals & hashCode methods implemented...

}

现在在我用值填充实体对象的客户端代码中,我已经这样做了:

PurchaseOrderCost cost = PurchaseOrderCost.builder()
                .id(PurchaseOrderCostPK.builder()
                        .costTypeId(costTypeEntry.getLovEntryId())
                        .purchaseOrderDetailId(purchaseOrderDetailParent.getId())
                        .build())

当我从 PurchaseOrderRepository 调用保存并正确设置所有子对象时,我遇到了这个问题:

2020-02-04 16:14:09 [http-nio-8080-exec-2] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-01400: cannot insert NULL into ("<SCHEMA>"."PURCHASE_ORDER_COST"."PURCHASE_ORDER_DETAIL_ID")
2020-02-04 16:14:10 [http-nio-8080-exec-2] ERROR o.h.i.ExceptionMapperStandardImpl - HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
2020-02-04 16:16:37 [http-nio-8080-exec-2] ERROR c.r.e.e.EnterpriseExceptionHandler - EnterpriseExceptionHandler:  
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:296)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

【问题讨论】:

    标签: spring-boot jpa spring-data


    【解决方案1】:

    刚刚想通了,我只需要在 PurchaseOrderCost 实体中添加以下注释:

    @Entity
    @Table(name="PURCHASE_ORDER_COST")
    public class PurchaseOrderCost implements Serializable {
    
        @EmbeddedId
        private PurchaseOrderCostPK id;
    
        @ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
        @MapsId("purchaseOrderDetailId")
        @JoinColumn(name="PURCHASE_ORDER_DETAIL_ID", insertable = false, updatable = false)
        private PurchaseOrderDetail purchaseOrderDetailByCost;
    
        //.. other fields..
    }
    

    即我们必须用属性名定义@MapsId("&lt;embadable_fk_property_name&gt;")注解,在我的例子中是PurchaseOrderCostPK.purchaseOrderDetailId

    【讨论】:

      猜你喜欢
      • 2018-01-13
      • 1970-01-01
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      • 2011-05-25
      • 2017-09-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多