6

重要なお知らせ :この投稿を読んでいる場合は、詳細な議論のためにこの投稿も検討することを検討してください。


親の子が別の親に移行される可能性があるのは、非常に一般的な慣行/状況/要件です。このような関係の逆側に をorphanRemoval設定するとどうなりますか?true

例として、次のような単純な 1 対多の関係を考えてみましょう。

裏側(部門):

@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employeeList = new ArrayList<Employee>(0);

所有側(従業員):

@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private Department department;

次のような操作/アクションをマージしながら (departmentはクライアントから提供された切り離されたエンティティです)、

Employee employee = entityManager.find(Employee.class, 1L);
Department newDepartment = entityManager.contains(department) ? department : entityManager.merge(department);

if (!newDepartment.equals(employee.getDepartment())) {
    employee.getDepartment().getEmployeeList().remove(employee);
    // Since orphanRemoval is set to true, 
    // this should cause a row from the database table to be removed inadvertently
    // by issuing an addition DELETE DML statement.
}

employee.setDepartment(newDepartment);
employee.setEmployeeName("xyz");        

List<Employee> employeeList = newDepartment.getEmployeeList();

if (!employeeList.contains(employee)) {
    employeeList.add(employee);
}

entityManager.merge(employee);

もちろん、従業員の追加と削除は、関連付けられたエンティティの防御リンク (関係) 管理メソッドを使用して行う/処理する方がよい場合があります。

部門インスタンスは、クライアントによって提供されます。切り離された存在です。問題のクライアントによって実行される管理アクションに応じて、同じ部門または異なる部門になる可能性があります。その結果、クライアントによって提供された部門インスタンスが現在の によって保持されているものと異なる場合、追加する前に、それに関連付けられている逆側の現在の古いEmployee部門によって保持されている従業員 ( ) のリストから最初に削除する必要があります。それは、新しく提供された従業員のリストに追加されます。employeeListEmployeedepartment

推測として、従業員の部門によって現在参照されている従業員のリストからインスタンスEmployeeを削除しているときに、データベースから行が誤って削除される必要がありますEmployee-古い部門(この操作がトリガーされる前)、つまり、子を親から別の親の場合、子は別の親に養子縁組される前にネイティブの親から削除する必要があり、その子の行はデータベースから誤って削除されることになっています ( orphanRemoval = true)。

ただし、データベース テーブルの従業員行は、更新された列の値でそのまま残ります。ステートメント以外の DML ステートメントUPDATEは生成されません。

このように子を親から別の親に移行すると、データベース テーブルからそれらの子が誤って削除されることはありません。

現在、JPA 2.1 を持つ EclipseLink 2.6.0 を使用しています。


編集:

Employee逆側のリストからエンティティが削除されるだけの場合 (つまり、削除後にリストに追加されず、別の親に移行されずに削除されただけ)、対応する行も通常どおりデータベースから削除されます( orphanRemoval = true)ただし、Employeeエンティティ (子) がネイティブの親のリストから削除された後 (エンティティの移行)、エンティティ (子) が別の親のリストに追加されると、行は単純に更新されます。

プロバイダーは、親から別の親への子の移行を更新として検出するのに十分スマートであるように見えます。

この動作は、Hibernate (4.3.6 final) と EclipseLink (2.6.0) の両方で同じように見えますが、プロバイダー固有の動作 (移植性がない) である場合、信頼できません。JPA仕様では、この動作について何も見つかりません。

4

1 に答える 1