JPA 2.0 orphanRemoval
属性について少し混乱しています。
JPAプロバイダーのDB生成ツールを使用ON DELETE CASCADE
して、特定の関係を持つ基礎となるデータベースDDLを作成するときに必要になると思います。
ただし、DBが存在し、すでにON DELETE CASCADE
関係が存在する場合、これは削除を適切にカスケードするには不十分ですか?orphanRemoval
さらに、何をしますか?
乾杯
JPA 2.0 orphanRemoval
属性について少し混乱しています。
JPAプロバイダーのDB生成ツールを使用ON DELETE CASCADE
して、特定の関係を持つ基礎となるデータベースDDLを作成するときに必要になると思います。
ただし、DBが存在し、すでにON DELETE CASCADE
関係が存在する場合、これは削除を適切にカスケードするには不十分ですか?orphanRemoval
さらに、何をしますか?
乾杯
回答:
orphanRemoval
とは何の関係もありませんON DELETE CASCADE
。
orphanRemoval
完全にORM固有のものです。「子」エンティティが「親」エンティティから参照されなくなった場合、たとえば、対応する親エンティティのコレクションから子エンティティを削除した場合に、「子」エンティティが削除されるようにマークします。
ON DELETE CASCADE
あるデータベース固有のものは、「親」の行が削除されると、それはデータベースに「子」の行を削除します。
ここでフォームを使用した例:
場合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も自動的に追加されます。
department.remove(emp);
、その従業員を呼び出すとすぐに、呼び出しさえせずにempテーブルから削除されますcommit()
DDL ON DELETE CASCADE
と同等のJPAマッピングはcascade=CascadeType.REMOVE
です。孤立した削除とは、「親」エンティティとの関係が破壊されると、依存エンティティが削除されることを意味します。たとえば@OneToMany
、エンティティマネージャで明示的に削除せずに子を関係から削除した場合などです。
cascade=CascadeType.REMOVE
はと同等ではありませんON DELETE CASCADE
。オンにすると、アプリケーションコードで削除され、DDLには影響しません。その他はDBで実行されます。stackoverflow.com/a/19696859/548473を
違いは次のとおりです。
-orphanRemoval = true:「子」エンティティは、参照されなくなると削除されます(その親は削除されない場合があります)。
-CascadeType.REMOVE:「親」が削除された場合にのみ「子」エンティティが削除されます。
これは非常に一般的な質問であるため、この回答に基づいてこの記事を作成しました。
JPAは、エンティティの状態遷移を、INSERT、UPDATE、DELETEなどのSQLステートメントに変換します。
persist
エンティティの場合、INSERTステートメントがEntityManager
、自動または手動でフラッシュされたときに実行されるようにスケジュールします。
ときに、remove
エンティティは、永続コンテキストがフラッシュされるときに実行されるDELETEステートメントを、スケジュールされています。
便宜上、JPAでは、エンティティの状態遷移を親エンティティから子エンティティに伝播できます。
したがって、子エンティティとの関連付けをPost
持つ親エンティティがある場合:@OneToMany
PostComment
エンティティのcomments
コレクションはPost
次のようにマッピングされます。
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
このcascade
属性は、エンティティの状態遷移を親Post
エンティティからコレクションにPostComment
含まれるすべてのエンティティに渡すようにJPAプロバイダーに指示しますcomments
。
したがって、Post
エンティティを削除すると、次のようになります。
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
JPAプロバイダーはPostComment
最初にエンティティを削除します。すべての子エンティティが削除されると、エンティティも削除さPost
れます。
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
orphanRemoval
属性をtrue
に設定するとremove
、子エンティティがコレクションから削除されたときに、JPAプロバイダーが操作をスケジュールします。
したがって、私たちの場合、
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());
post.getComments().remove(postComment);
エンティティがコレクションで参照されなくなっpost_comment
たため、JPAプロバイダーは関連するレコードを削除PostComment
しcomments
ます。
DELETE FROM post_comment WHERE id = 1
ON DELETE CASCADE
FKレベルで定義されています。
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
post
行したら、行を削除すると、次のようになります。
DELETE FROM post WHERE id = 1
関連post_comment
するすべてのエンティティは、データベースエンジンによって自動的に削除されます。ただし、誤ってルートエンティティを削除した場合、これは非常に危険な操作になる可能性があります。
JPA cascade
とorphanRemoval
オプションの利点は、楽観的ロックを利用して更新の損失を防ぐこともできることです。
JPAカスケードメカニズムを使用する場合、DDLレベルを使用する必要はありませんON DELETE CASCADE
。これは、複数のレベルに多数の子エンティティを持つルートエンティティを削除する場合、非常に危険な操作になる可能性があります。
このトピックの詳細については、こちらの記事をご覧ください。
CascadeType
。それは補完的なメカニズムです。今、あなたは削除を永続化と間違えています。孤立した削除とは、参照されていない関連付けを削除することであり、永続化は新しいエンティティを保存することです。これらの概念をよりよく理解するには、回答に記載されているリンクをたどる必要があります。
@GaryKの答えは、私が説明を探して時間を費やしてきた、絶対に素晴らしいですorphanRemoval = true
対CascadeType.REMOVE
、それは私が理解して助けました。
まとめ:オブジェクト()を削除し、子オブジェクトも削除したい場合のみ、orphanRemoval = true
同じように機能します。CascadeType.REMOVE
entityManager.delete(object)
まったく異なる状況で、のようなデータをフェッチしList<Child> childs = object.getChilds()
てから子(entityManager.remove(childs.get(0)
)を削除すると、にorphanRemoval=true
対応するエンティティ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)。
学生テーブル:-
1ロイECE 1
2ニックECE 1
1ジョン$ 1500
そして、私が生徒の一人を削除したい場合は、
Student student1 = em.find(Student.class,1);
em.remove(student1);
生徒のレコードが削除されると、対応するガイドレコードも削除されます。この場合、生徒エンティティのCASCADE.REMOVE属性が機能し、何が行われるかがわかります。これにより、識別子1の生徒と対応するガイドオブジェクト(識別子)が削除されます。 1)。ただし、この例では、同じガイドレコードにマップされるもう1つの生徒オブジェクトがあり、Guide EntityでorphanRemoval = true属性を使用しない限り、上記の削除コードは機能しません。