8

我有一个实体类Payment ,它具有具有多对一关系的实体类PaymentMethod

现在因为 My PaymentMethod 是主表。

所以我想在不影响主表 PaymentMethod 的情况下保存付款。

但是每次我保存付款时,它都会在 PaymentMethod 中插入新行。我无法弄清楚为什么。

我正在使用 SpringData 保存。

支付.java

@Entity
@Table(name="payment")
public class Payment implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;

   @ManyToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE,CascadeType.PERSIST})
   @JoinColumn(name="payment_method_id")
   private PaymentMethod paymentMethod;

  //getter and setters
}

PaymentMethod.java

@Table(name="paymentmethod")
 public class PaymentMethod implements Serializable {
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 @Column(name="name",unique=true ,nullable=false)
 private String name;

 //GETTER AND SETTERS
}

PAYMENT_METHOD 数据

ID | NAME 
1  | AA
2  | BB
3  | CC

付款后保存 PAYMENT_METHOD 条目与重复名称?

我无法弄清楚为什么?

为了节省,我为付款类型创建了简单的 CRUDRepository

调用存储库的保存实体。

请建议我在哪里摔倒。

每当代码执行此行时:

paymentMethodRepository.findByName(payment.getPaymentMethod().getName());

它给出了错误

Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.enrollment.domain.Payment.paymentMethod -> com.enrollment.domain.PaymentMethod
    at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:176)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
    at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
    at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:448)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
    at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
    at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:448)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
    at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
    at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
    at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
    at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
    at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
    at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
    at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:160)
    at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:151)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1186)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1241)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
    at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:285)

当我从存储库调用 finder 方法时,如果尝试刷新代码,我无法弄清楚代码如何。

我错过了什么吗?

感谢@JB 和@spiritwalker 解决了问题,但无法找到确切的根本原因,所以只讨论行为可能是讨论会增加太多知识。

Behaviour ..

Open Transaction
   1. validate
   2. save child
   3. validate and update 
   4. save parent
Close Transaction

it was giving above error.

Now, after code change it worked

Open Transaction
   1. validate
   2. validate and update 
   3. save child
   4. save parent
Close Transaction
4

2 回答 2

4

首先删除级联,因为您在创建/修改付款时不希望创建/修改 PaymentMethod。

然后,当您创建 Payment 时,为其分配您希望与其关联的现有 PaymentMethod:

PaymentMethod existingPaymentMethod = em.find(PaymentMethod.class, idOfThePaymentMethod);
Payment payment = new Payment();
payment.setPaymentMethod(existingPaymentMethod);
em.persist(payment);
于 2013-02-17T09:35:22.587 回答
3

从您的支付实体中删除cascade={CascadeType.REFRESH,CascadeType.MERGE,CascadeType.PERSIST} 。

由于 PaymentMethod 是您所说的主表,因此您不希望从 Payment 到 PaymentMethod 发生任何级联操作。

于 2013-02-17T09:32:59.897 回答