Hibernate / JPA не может установить идентификатор родителя для ключа кандидата ребенка - PullRequest
0 голосов
/ 05 февраля 2020

Вот пример кода:

Родитель:

@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())

Когда я вызываю команду save из 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)

1 Ответ

0 голосов
/ 05 февраля 2020

Только что понял, мне нужно добавить только аннотацию ниже в объекте 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("<embadable_fk_property_name>") с именем свойства, которое в моем случае равно PurchaseOrderCostPK.purchaseOrderDetailId

...