JPA 2.0 orphanRemoval
属性について少し混乱しています。
JPAプロバイダーのDB生成ツールを使用して、特定のリレーションにON DELETE CASCADE
を持つように基になるデータベースDDLを作成するときに必要だと思うと思います。
ただし、DBが存在し、リレーションに既にON DELETE CASCADE
がある場合、これは削除を適切にカスケードするのに十分ではありませんか? orphanRemoval
はさらに何をしますか?
乾杯
orphanRemoval
はON DELETE CASCADE
とは関係ありません。
orphanRemoval
は完全にORM固有のものです。 「親」エンティティから参照されなくなったときに削除される「子」エンティティをマークします。親エンティティの対応するコレクションから子エンティティを削除するとき。
ON DELETE CASCADE
はデータベース固有のものです。「親」行が削除されると、データベースの「子」行が削除されます。
here の形式の例:
Employee
エンティティオブジェクトが削除されると、削除操作は参照されるAddress
エンティティオブジェクトにカスケードされます。この点で、orphanRemoval=true
とcascade=CascadeType.REMOVE
は同一であり、orphanRemoval=true
が指定されている場合、CascadeType.REMOVE
は冗長です。
2つの設定の違いは、関係の切断に対する応答にあります。たとえば、アドレスフィールドをnull
または別のAddress
オブジェクトに設定する場合など。
orphanRemoval=true
が指定されている場合、切断されたAddress
インスタンスは自動的に削除されます。これは、所有者オブジェクト(たとえば、Address
)からの参照なしでは存在しないはずの依存オブジェクト(たとえば、Employee
)をクリーンアップするのに役立ちます。
cascade=CascadeType.REMOVE
のみが指定されている場合、関係の切断は削除操作ではないため、自動アクションは実行されません。
孤立した削除の結果として参照がぶら下がるのを避けるために、この機能はプライベートな非共有依存オブジェクトを保持するフィールドに対してのみ有効にする必要があります。
これがより明確になることを願っています。
コレクションから子エンティティを削除すると、その子エンティティもDBから削除されます。 orphanRemovalは、親を変更できないことも意味します。従業員がいる部門がある場合、その従業員を削除して別の部門に入れると、flush/commit(どちらが先でも)でDBからその従業員を誤って削除してしまいます。その親の子が存在する間、別の親に移行しないことが確実である限り、士気はorphanRemovalをtrueに設定することです。 orphanRemovalをオンにすると、カスケードリストにREMOVEも自動的に追加されます。
DDL ON DELETE CASCADE
に相当するJPAマッピングはcascade=CascadeType.REMOVE
です。孤立した削除とは、「親」エンティティとの関係が破棄されたときに依存エンティティが削除されることを意味します。たとえば、エンティティマネージャで明示的に削除せずに@OneToMany
関係から子が削除された場合。
@GaryKの答えは絶対に素晴らしいです。説明を探してorphanRemoval = true
対CascadeType.REMOVE
を探して、理解するのに役立ちました。
まとめ:orphanRemoval = true
はCascadeType.REMOVE
と同じように機能しますONLY IFオブジェクトを削除し(entityManager.delete(object)
)、childsオブジェクトも削除したいです。
完全に異なる状況では、List<Child> childs = object.getChilds()
のようなデータをフェッチし、orphanRemoval=true
を使用して子(entityManager.remove(childs.get(0)
)を削除すると、childs.get(0)
に対応するエンティティがデータベースから削除されます。
孤立した削除は、次のシナリオでON DELETE CASCADEと同じ効果があります:-学生エンティティとガイドエンティティ間に単純な多対1の関係があり、多くの学生が同じガイドにマッピングでき、データベースにあるとしましょうstudentテーブルがFKとしてid_guideを持つような、StudentテーブルとGuideテーブル間の外部キー関係。
@Entity
@Table(name = "student", catalog = "helloworld")
public class Student implements Java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name = "id_guide")
private Guide guide;
//親エンティティ
@Entity
@Table(name = "guide", catalog = "helloworld")
public class Guide implements Java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 9017118664546491038L;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;
@Column(name = "name", length = 45)
private String name;
@Column(name = "salary", length = 45)
private String salary;
@OneToMany(mappedBy = "guide", orphanRemoval=true)
private Set<Student> students = new HashSet<Student>(0);
このシナリオでは、関係は、学生エンティティが関係の所有者であるため、オブジェクトグラフ全体を永続化するために、学生エンティティを保存する必要があります。
Guide guide = new Guide("John", "$1500");
Student s1 = new Student(guide, "Roy","ECE");
Student s2 = new Student(guide, "Nick", "ECE");
em.persist(s1);
em.persist(s2);
ここでは、2つの異なる学生オブジェクトを使用して同じガイドをマッピングしています。CASCADE.PERSISTが使用されているため、オブジェクトグラフは以下のようにデータベーステーブルに保存されます(私の場合はMySql)
STUDENTテーブル:-
1 Roy ECE 1
2ニックECE 1
1ジョン1500ドル
そして今、私は学生の一人を削除したい場合は、使用して
Student student1 = em.find(Student.class,1);
em.remove(student1);
学生レコードが削除されると、対応するガイドレコードも削除される必要があります。これは、StudentエンティティのCASCADE.REMOVE属性が表示される場所であり、その処理は識別子1の学生と対応するガイドオブジェクト(識別子1)。ただし、この例では、同じガイドレコードにマップされるもう1つの学生オブジェクトがあり、Guide EntityでorphanRemoval = true属性を使用しない限り、上記の削除コードは機能しません。
違いは:
-orphanRemoval = true:「子」エンティティは、参照されなくなったときに削除されます(その親は削除できません)。
-CascadeType.REMOVE:「子」エンティティは、「親」が削除された場合にのみ削除されます。