层次结构中的子级删除和JPA查询执行顺序问题

时间:2019-06-16 16:22:58

标签: java hibernate mapping hierarchy openjpa

我有一个ContractPhase

Contract存储Phase的列表。

Phase被实现为层次结构:具有父Phase和子列表Phase

映射代码为:

public class Contract {
    @OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Phase> phases;
}

public class Phase {
    private String display_no;

    @ManyToOne
    @JoinColumn(name = "contract_no", referencedColumnName = "contract_no", insertable = false, updatable = false)
    private Contract contract;

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "contract_no", referencedColumnName = "contract_no", insertable = false, updatable = false),
        @JoinColumn(name = "parent_phase_no", referencedColumnName = "phase_no", insertable = false, updatable = false) })
    private Phase parentPhase;

    @OneToMany(mappedBy = "parentPhase", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Phase> subPhases;
}

假设我有Contract个CTR1及其Phase(phase_no | display_no):

  • 1 | 1个
    • 2 | 1.1
      • 3 | 1.1.1
      • 4 | 1.1.2
    • 5 | 1.2
  • 6 | 2

然后,我要删除Phase 1.1及其子级。我有一个名为selectedPhses的变量,包含将按照子对父顺序删除的阶段:[1.1.21.1.11.1](因为我认为一个阶段可以是仅在删除其子级后删除)

// selectedPhses = [1.1.2 , 1.1.1 , 1.1]
for (Phase phs : selectedPhses) {
    Phase parent = phs.getParentPhase();

    // delete phase from parent
    if (parent != null) {
        parent.getSubPhases().remove(phs);
    }

    // delete phase from contract
    contract.getPhases().remove(phs);

    // entityManager.flush();
}

正如我从上述代码中所期望的那样,将首先删除1.1.2,然后删除1.1.1,最后删除1.1。我还在@PreRemove创建了一个侦听器,以查看删除顺序。正确(4-> 3-> 2):

DEBUG [2019-06-16 22:20:42,555] th.entity.Phase(preRemove:529) - Removing th.entity.Phase[PK: (contract_no=CTR1;phase_no=4;)];
DEBUG [2019-06-16 22:20:42,555] th.entity.Phase(preRemove:529) - Removing th.entity.Phase[PK: (contract_no=CTR1;phase_no=3;)];
DEBUG [2019-06-16 22:20:42,556] th.entity.Phase(preRemove:529) - Removing th.entity.Phase[PK: (contract_no=CTR1;phase_no=2;)];

但是当jpa执行DELETE查询时,其顺序与上面的日志不同(2-> 4-> 3):

executing prepstmnt 661533276 DELETE FROM Phase WHERE contract_no= ? AND phase_no= ? [params=(String) CTR1, (int) 2]
executing prepstmnt 661533276 DELETE FROM Phase WHERE contract_no= ? AND phase_no= ? [params=(String) CTR1, (int) 4]
executing prepstmnt 661533276 DELETE FROM Phase WHERE contract_no= ? AND phase_no= ? [params=(String) CTR1, (int) 3]

执行顺序违反db约束并引发Exception。我通过在for循环(注释行)的末尾添加flush()进行了测试,并且可以正常工作。但是很多人不推荐flush(),所以我不会使用它。

问题是:

  1. 为什么订单不同? jpa是否对查询重新排序?
  2. 如何避免这种情况并使jpa按预期的顺序运行?我的映射正确吗?

谢谢!

0 个答案:

没有答案