JPA:単方向多対1およびカスケード削除


95

私が持っていると言う一方向の @ManyToOne次のような関係を:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;
}

@Entity
public class Child implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne
    @JoinColumn
    private Parent parent;  
}

Pを参照する親Pと子C 1 ... C nがある場合、JPには、Pが削除されたときに(つまり)子C 1 ... C nを自動的に削除するクリーンできれいな方法がありentityManager.remove(P)ますか?

私が探しているのは、ON DELETE CASCADESQL と同様の機能です。


1
「子」だけが「親」への参照を持っている場合でも(そのように参照は単方向です)、「@ OneToMany」マッピングと「Cascade = ALL」属性を使用して「子」のリストを追加することは問題があります。親'?私は、JPAがタフな片側だけが参照を保持することを解決する必要があると思います。
kvDennis 2011

1
@kvDennis、多面を片面に密結合したくない場合があります。たとえば、セキュリティ権限が透過的な「アドオン」であるACLのような設定
Bachi

回答:


73

親を子に双方向で関連付けない限り、JPAの関係は常に単方向です。親から子へのREMOVE操作のカスケードには、親から子へのリレーションが必要になります(反対だけではありません)。

したがって、これを行う必要があります。

  • 単方向の@ManyToOne関係を双方向@ManyToOne、または単方向に変更してください@OneToMany。その後、REMOVE操作をカスケードしてEntityManager.remove、親と子を削除できます。またorphanRemoval、trueを指定して、親コレクションの子エンティティがnullに設定されているときに孤立した子を削除することもできます。つまり、親のコレクションに存在しない子を削除します。
  • または、子テーブルで外部キー制約をとして指定しますON DELETE CASCADE。永続化コンテキストを更新する必要があるため、呼び出しEntityManager.clear()後に呼び出す必要があります。EntityManager.remove(parent)子エンティティは、データベースから削除された後、永続化コンテキストに存在することはありません。

7
JPAアノテーションでNo2を行う方法はありますか?
user2573153 14

3
Hibernate xmlマッピングでNo2を実行するにはどうすればよいですか?
arg20 2014年

92

JPAプロバイダーとしてhibernateを使用している場合は、@ OnDeleteアノテーションを使用できます。この注釈は、リレーションにトリガーON DELETE CASCADEを追加し、子の削除をデータベースに委任します。

例:

public class Parent {

        @Id
        private long id;

}


public class Child {

        @Id
        private long id;

        @ManyToOne
        @OnDelete(action = OnDeleteAction.CASCADE)
        private Parent parent;
}

このソリューションでは、子から親への一方向の関係で、すべての子を自動的に削除できます。このソリューションはリスナーなどを必要としません。また、DELETE FROM Parent WHERE id = 1のようなクエリは子を削除します。


4
この方法で動作させることはできません。Hibernateの特定のバージョン、またはこのような他のより詳細な例はありますか?
Mardari 2017年

3
それがなぜあなたのために働いていないのかを言うのは難しいです。これを機能させるには、スキーマを再生成する必要があるか、カスケード削除を手動で追加する必要があります。@OnDeleteアノテーションはしばらくの間存在しているようですが、バージョンが問題であるとは思いません。
Thomas Hunziker 2017年

10
答えてくれてありがとう。クイックノート:データベースカスケードトリガーは、休止状態によるDDL生成を有効にした場合にのみ作成されます。それ以外の場合は、「DELETE FROM Parent WHERE id = 1」のようにDBに対してアドホッククエリを直接実行できるように、別の方法(liquibaseなど)で追加する必要があります。カスケード削除を実行します。
mjj1409 2017年

1
関連付けが@OneToOne有効な場合、これは機能しません@OneToOne
stakowerflol 2018

1
@ThomasHunzikerこれはorphanRemovalでは機能しませんよね?
oxyt

13

次のように、双方向の関係を作成します。

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private Set<Child> children;
}

8
悪い答えです。大きな子供たちのセットを操作するのに信じられないほどの時間がかかるため、JPAでは双方向の関係がひどい
Enerccio

1
双方向の関係が遅いという証拠はありますか?
shalama

@enerccio双方向の関係が1対1の場合はどうなりますか?また、双方向の関係が遅いという記事を見せてください。何が遅い?取得していますか?削除しますか?アップデート?
saran3h

@ saran3hすべての操作(追加、削除)はすべての子をロードするので、それは役に立たない可能性がある巨大なデータロードです(値を追加する場合、データベースからすべての子をロードする必要はなく、このマッピングはまさにこのようなものです)。
Enerccio

@Enerccio誰もが結合で遅延読み込みを使用していると思います。それでも、パフォーマンスの問題はどうですか?
saran3h

1

一方向の@ManytoOneで見たことがありますが、削除は期待どおりに機能しません。親が削除されると、理想的には子も削除されますが、親のみが削除され、子は削除されず、孤立したままになります

使用されているテクノロジーは、Spring Boot / Spring Data JPA / Hibernateです。

スプリントブート:2.1.2.RELEASE

Spring Data JPA / Hibernateを使用して行.egを削除します

parentRepository.delete(parent)

ParentRepositoryは、以下に示すように標準CRUDリポジトリを拡張します ParentRepository extends CrudRepository<T, ID>

以下は私のエンティティクラスです

@Entity(name = child”)
public class Child  {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne( fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = parent_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;
}

@Entity(name = parent”)
public class Parent {

    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false, length = 50)
    private String firstName;


}

削除が機能しない理由の解決策を見つけました。どうやらhibernateはmysqlエンジン-INNODBを使用していませんでした。mysqlが外部キー制約を生成するには、エンジンINNODBが必要です。application.propertiesで次のプロパティを使用すると、Spring Boot / HibernateでmysqlエンジンINNODBを使用できます。そのため、外部キー制約が機能し、カスケードも削除されます
ランジェッシュ

欠落したプロパティは、以前のコメントで使用されています。使用されるばね特性は次のとおりですspring.jpa.hibernate.use-new-id-generator-mappings=true spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
ランジェシュ

ちなみに、"コードに誤りがあります。参照name= "parent"
アレクサンダー

0

この方法を使用して、片側のみを削除します

    @ManyToOne(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
//  @JoinColumn(name = "qid")
    @JoinColumn(name = "qid", referencedColumnName = "qid", foreignKey = @ForeignKey(name = "qid"), nullable = false)
    // @JsonIgnore
    @JsonBackReference
    private QueueGroup queueGroup;

-1

@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

与えられた注釈は私にとってうまくいきました。試すことができます

例えば ​​:-

     public class Parent{
            @Id
            @GeneratedValue(strategy=GenerationType.AUTO)
            @Column(name="cct_id")
            private Integer cct_id;
            @OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true)
            @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
            private List<Child> childs;
        }
            public class Child{
            @ManyToOne(fetch=FetchType.EAGER)
            @JoinColumn(name="cct_id")
            private Parent parent;
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.