TransientPropertyValueException: 对象引用了一个未保存的瞬时实例 - 在执行flush操作之前先保存该瞬时实例。

4

我有两个Hibernate实体Coupon和CouponHistory,它们之间存在单向关系。

@Entity
@Table(name = "validity_coupon")
public class Coupon {

@Id
@Column(length = 50, unique = true, nullable = false)
private String code;

private int validity;
private boolean used;

...}


@Entity
@Table(name = "coupon_history")
@TableGenerator(name = "seqGen", table = "shunya_id_gen", pkColumnName = "GEN_KEY", valueColumnName = "GEN_VALUE",
    pkColumnValue = "coupon_history_seq", allocationSize = 1)
public class CouponHistory {

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "seqGen")
private long id;

@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;

@ManyToOne(fetch = FetchType.LAZY)
private Coupon coupon;

...}

这里有一个事务性服务方法,它尝试在一次事务中保存两个实体。在这里使用Spring来处理事务。

@Transactional
public void createCoupon() {
    Coupon coupon = new Coupon();
    coupon.setCode(RandomStringUtils.randomAlphanumeric(5));
    coupon.setValidity(1);
    couponRepository.save(coupon);

    CouponHistory couponHistory = new CouponHistory();
    couponHistory.setCreatedOn(new Date());
    couponHistory.setCoupon(coupon);
    couponHistoryRepository.save(couponHistory);
}

当我调用这个方法时,我会遇到以下异常 -
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance beforeQuery flushing : com.poc.CouponHistory.validityCoupon -> com.poc.Coupon; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance beforeQuery flushing : com.poc.CouponHistory.validityCoupon -> com.poc.Coupon

我不明白为什么在单个事务中先保存子实体再保存父实体时,Hibernate会抱怨我。
如果我将Coupon Entity的ID生成方式更改为自动,则一切都开始正常工作。但是,我想手动分配优惠券代码,因此ID自动生成不在考虑范围内。
任何帮助将不胜感激!
2个回答

2

如果您不是级联优惠券,那么在保存CouponHistory之前需要对其进行管理。幸运的是,在保存实体时,save()将返回已管理的持久化实体,所以您只需要将其分配给coupon。

 @Transactional
public void createCoupon() {
Coupon coupon = new Coupon();
coupon.setCode(RandomStringUtils.randomAlphanumeric(5));
coupon.setValidity(1);
coupon = couponRepository.save(coupon);//save will return the managed entity

CouponHistory couponHistory = new CouponHistory();
couponHistory.setCreatedOn(new Date());
couponHistory.setCoupon(coupon);
couponHistoryRepository.save(couponHistory);
}

仓储的保存方法是否返回一个新实例?我认为保存对象会被分配一个ID,这是我的印象。 - Munish Chandel
@MunishChandel 是的,它返回与持久性上下文相关联的新实例。 - Amer Qarabsa

1
尝试使用@PersistenceContext将实体管理器连接起来,保存Coupon后执行this.entityManager.flush()。Hibernate通常会尽可能地等待持久化实体(通常是直到事务关闭),您可以通过显式刷新来“强制”它进行持久化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接