当新的子实体持久化时,父实体不必要地被更新。

3
我们正在使用JPA实体和Hibernate进行持久化。 我有一个“计划”实体和一个“升级”实体。 当我创建并持久化一个新的升级时,计划也会被更新。 这个更新导致了“OptimisticLockException”,并阻止了进一步的升级被持久化。以下是代码骨架 -
@Entity
@Table(name = "T_ESCLT")
public class Escalation extends PersistentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ESCLT_ID")
    private Integer id;

    @ReflectionCopy.Exclude
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CUST_RNEW_TASK_ID", nullable = false)
    private CustomerRenewalTask renewalTask;

    @ReflectionCopy.Exclude
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PLN_DSG_ID")
    private Plan plan;

public Escalation(CustomerRenewalTask task, Plan plan, String description) {
        Preconditions.checkNotNull(task);
        Preconditions.checkNotNull(description);

        this.renewalTask = task;
        this.plan = plan;
        this.description = description;
        this.creationTimestamp = DateUtils.currentTimestamp();
    }

PlanCustomerRenewalTask中没有映射升级。 当我运行这个程序时

@Transactional
    public Result persist() {
        CustomerRenewalTask customerRenewalTask = customerRenewalTaskDao.findById(2);
        Plan plan = planDao.findById(16);
        planDao.detach(plan);
        Escalation escalation = new Escalation(customerRenewalTask, plan, "My Escalation");
        escalationDao.persist(escalation);
        return ok();
    }

我在控制台日志中看到了这个。
DEBUG - insert into T_ESCLT (ESCLT_ID, OPTMSTC_LOCK_ID, ATRB_NM, CMNT_TXT, CRT_TS, ESCLT_DSCR, APP_LNK_TXT, PLN_DSG_ID, RT_BLCK_IND, CUST_RNEW_TASK_ID, RSLV_DT, RSLV_BY_USR_ID, RSLV_BY_USR_NM, ESCLT_STTS_CD, ESCLT_TYP_CD) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
DEBUG - update T_PLN_DSG set OPTMSTC_LOCK_ID=?, ASSOC_PLN_DSG_ID=?, BRTH_DT_RT_IND=?, PLN_EFF_DT=?, ELGBL_MBR_CNT=?, RNEW_PLN_DTL_XML=?, SUM_MBR_PRTCP_LIF_CNT=?, VLD_STTS_CD=?, PLN_NM=?, PLN_GRP_ID=?, PRNT_PLN_DSG_ID=?, PRTCP_MBR_CNT=?, PRTCP_PCT=?, PRTNR_PLN_DSG_ID=?, RT_CALC_XML=?, UW_VRFY_IND=?, SUM_VOL_AMT=? where PLN_DSG_ID=? and OPTMSTC_LOCK_ID=?

我不希望发布关于计划更新的通知,因为计划并没有发生任何变化。我只是使用计划来创建一个升级。


1
你可能正在执行 planDao.detach(plan) 的操作,这会更新 Plan 实体的属性吗? - Franck
请发布Plan实体的映射以及PlanDao中相关方法的实现。 - Dragan Bozanovic
根据定义,您必须对“Plan”执行某些操作,这会导致Hibernate认为它是“脏的”,并且需要在“flush()”时进行更新。 - Dean Clark
我不得不添加planDao.detach(plan);,它只是执行em().detach(plan);。这样可以防止对Plan的更新,但是在代码审查中,这个解决方案被否决了。Plan和Escalation具有单向一对多映射,因此在Plan中没有升级属性。我在持久化升级之前和之后打印了plan对象,并且我没有看到任何区别。我没有做任何使计划变脏的事情,但是Hibernate认为不同。 - Vinay
1个回答

1
一种阻止更新发生的方法是为Plan实体的各个属性指定update=false,但这样做会完全阻止在Plan表上进行更新。
请检查是否指定cascade=CascadeType.PERSIST可以解决您的问题。
@ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST)

我在升级中尝试了以下代码: @JoinColumn(name = "PLN_DSG_ID") @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) private Plan plan; 但是我仍然可以在控制台日志中看到升级插入和计划更新的SQL。 - Vinay

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