212

JPA2.0orphanRemoval属性について少し混乱しています。

ON DELETE CASCADEJPAプロバイダーのDB生成ツールを使用して、特定の関係を持つ基盤となるデータベースDDLを作成するときに、これが必要であることがわかると思います。

ただし、DBが存在し、すでにON DELETE CASCADE関係にある場合、これは削除を適切にカスケードするのに十分ではありませんか?さらに何orphanRemovalをしますか?

乾杯

4

8 に答える 8

333

orphanRemovalとは何の関係もありませんON DELETE CASCADE

orphanRemoval完全にORM固有のものです。これは、「親」エンティティから参照されなくなったとき、たとえば、親エンティティの対応するコレクションから子エンティティを削除したときに、「子」エンティティを削除するようにマークします。

ON DELETE CASCADEデータベース固有のものであり、「親」行が削除されると、データベースの「子」行が削除されます。

于 2010-12-01T22:18:00.890 に答える
118

ここにある例:

Employeeエンティティオブジェクトが削除されると、削除操作は参照されているエンティティオブジェクトにカスケードされますAddress。この点で、orphanRemoval=truecascade=CascadeType.REMOVEは同一であり、orphanRemoval=true指定されている場合CascadeType.REMOVEは冗長です。

2つの設定の違いは、関係の切断に対する応答にあります。たとえば、アドレスフィールドnullを別のAddressオブジェクトに設定する場合などです。

  • が指定されている場合orphanRemoval=true、切断されたAddressインスタンスは自動的に削除されます。Addressこれは、所有者オブジェクト(eg)からの参照なしでは存在してはならない依存オブジェクト(eg)をクリーンアップするのに役立ちますEmployee

  • のみcascade=CascadeType.REMOVEが指定されている場合、関係の切断は削除操作ではないため、自動アクションは実行されません。

孤立した削除の結果として参照がぶら下がるのを防ぐために、この機能は、共有されていないプライベートな依存オブジェクトを保持するフィールドに対してのみ有効にする必要があります。

これがより明確になることを願っています。

于 2012-08-19T13:18:21.517 に答える
48

コレクションから子エンティティを削除すると、その子エンティティもDBから削除されます。orphanRemovalは、親を変更できないことも意味します。従業員がいる部門がある場合、その従業員を削除して別の部門に配置すると、フラッシュ/コミット(どちらか早い方)でその従業員を誤ってDBから削除してしまいます。士気は、その親の子がその存在を通じて別の親に移行しないことが確実である限り、orphanRemovalをtrueに設定することです。orphanRemovalをオンにすると、カスケードリストにREMOVEが自動的に追加されます。

于 2011-05-31T09:50:34.187 に答える
30

エンティティの状態遷移

JPAは、エンティティの状態遷移をINSERT、UPDATE、DELETEなどのSQLステートメントに変換します。

JPAエンティティの状態遷移

エンティティの場合、自動または手動でフラッシュpersistされたときに実行されるINSERTステートメントをスケジュールしています。EntityManager

エンティティの場合remove、永続コンテキストがフラッシュされたときに実行されるDELETEステートメントをスケジュールしています。

カスケードエンティティの状態遷移

便宜上、JPAを使用すると、エンティティの状態遷移を親エンティティから子エンティティに伝播できます。

したがって、子エンティティと関連付けられPostている親エンティティがある場合は、次のようになります。@OneToManyPostComment

PostおよびPostCommentエンティティ

エンティティ内のcommentsコレクションはPost次のようにマップされます。

@OneToMany(
    mappedBy = "post", 
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();

CascadeType.ALL

この属性は、JPAプロバイダーに、親エンティティからコレクションに含まれるすべてのエンティティcascadeへのエンティティ状態遷移を渡すように指示します。PostPostCommentcomments

したがって、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と、JPAプロバイダーはremove、子エンティティがコレクションから削除されたときに操作をスケジュールします。

したがって、私たちの場合、

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);

エンティティがコレクションで参照されなくなったため、JPAプロバイダーは関連するpost_commentレコードを削除します。PostCommentcomments

DELETE FROM post_comment WHERE id = 1

カスケードの削除について

ON DELETE CASCADEFKレベルで定義されています。

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エンティティは、データベースエンジンによって自動的に削除されます。ただし、誤ってルートエンティティを削除すると、これは非常に危険な操作になる可能性があります。

結論

JPAcascadeorphanRemovalオプションの利点は、更新の損失を防ぐために楽観的ロックの恩恵を受けることもできることです。

JPAカスケードメカニズムを使用する場合、DDLレベルを使用する必要はありませんON DELETE CASCADE。これは、複数のレベルに多数の子エンティティを持つルートエンティティを削除する場合に非常に危険な操作になる可能性があります。

于 2020-03-24T19:48:34.087 に答える
21

DDLの同等のJPAマッピングON DELETE CASCADEはですcascade=CascadeType.REMOVE。孤立した削除とは、「親」エンティティとの関係が破棄されたときに、依存エンティティが削除されることを意味します。たとえば@OneToMany、エンティティマネージャで子を明示的に削除せずに、子をリレーションシップから削除した場合です。

于 2010-12-01T22:17:01.827 に答える
15

違いは次のとおり
です。--orphanRemoval=true:「子」エンティティは、参照されなくなると削除されます(親は削除されない場合があります)。
--CascadeType.REMOVE:「子」エンティティは、その「親」が削除された場合にのみ削除されます。

于 2018-04-14T05:25:01.313 に答える
6

orphanRemoval = true@GaryKの答えは絶対に素晴らしいです、私は説明を探すのに1時間費やしました、CascadeType.REMOVEそしてそれは私が理解するのを助けました。

要約:オブジェクト()を削除し、子オブジェクトも削除する場合にのみorphanRemoval = true、同じように機能します。CascadeType.REMOVE entityManager.delete(object)

まったく異なる状況で、のようなデータをフェッチList<Child> childs = object.getChilds()してから子(entityManager.remove(childs.get(0))を削除orphanRemoval=trueすると、に対応するエンティティchilds.get(0)がデータベースから削除されます。

于 2015-09-09T15:03:59.310 に答える
3

孤立した削除は、次のシナリオで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)に次のように保存されます。

学生テーブル:-

ID名部Id_Guide

1ロイECE1

2ニックECE1

ガイド表:-

ID名給与

1ヨハネ$1500

そして今、私が学生の1人を削除したい場合は、

      Student student1 = em.find(Student.class,1);
      em.remove(student1);

学生レコードが削除されると、対応するガイドレコードも削除する必要があります。ここで、StudentエンティティのCASCADE.REMOVE属性が表示され、識別子1の学生と対応するガイドオブジェクト(識別子)が削除されます。 1)。ただし、この例では、同じガイドレコードにマップされているもう1つの学生オブジェクトがあり、ガイドエンティティでorphanRemoval = true属性を使用しない限り、上記の削除コードは機能しません。

于 2015-08-05T08:08:29.853 に答える