web-dev-qa-db-ja.com

単方向と双方向のJPAおよびHibernateアソシエーションの違いは何ですか?

単方向関連付けと双方向関連付けの違いは何ですか?

Dbで生成されたテーブルはすべて同じであるため、私が見つけた唯一の違いは、双方向の関連付けの各側が他方への参照を持ち、一方向ではないことです。

これは単方向の関連付けです

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}

public class Group {
    private int     id;
    private String  name;
}

双方向の関連付け

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}
public class Group {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="group")
    private List<User>  users;
}

違いは、グループがユーザーの参照を保持しているかどうかです。

だからこれが唯一の違いなのだろうか?どちらがお勧めですか?

120
hguser

主な違いは、双方向リレーションシップが双方向のナビゲーションアクセスを提供するため、明示的なクエリなしで反対側にアクセスできることです。また、カスケードオプションを両方向に適用できます。

特に「1対多」および「多対多」の関係では、ナビゲーションアクセスが常に良好であるとは限らないことに注意してください。何千ものGroupsを含むUserを想像してください:

  • どのようにアクセスしますか? Usersが非常に多いため、通常は何らかのフィルタリングやページネーションを適用する必要があるため、とにかくクエリを実行する必要があります( コレクションフィルタリング を使用する場合を除きます)。私)。このような場合、一部の開発者はメモリにフィルタリングを適用する傾向がありますが、これは明らかにパフォーマンスに良くありません。このような関係があると、パフォーマンスへの影響を考慮せずにこの種の開発者がそれを使用するように奨励できることに注意してください。

  • 新しいUsersをGroupにどのように追加しますか?幸いなことに、Hibernateはリレーションシップを保持するときにリレーションシップの所有側を確認するため、User.groupのみを設定できます。ただし、メモリ内のオブジェクトの一貫性を維持する場合は、UserGroup.usersに追加する必要もあります。しかし、それはHibernateがGroup.usersのすべての要素をデータベースからフェッチするようにします!

したがって、 ベストプラクティス の推奨事項に同意することはできません。ユースケース(両方向のナビゲーションアクセスが必要ですか?)およびパフォーマンスへの影響を考慮して、双方向の関係を慎重に設計する必要があります。

以下も参照してください:

132
axtavt

主に2つの違いがあります。

協会側へのアクセス

1つ目は、関係へのアクセス方法に関連しています。単方向の関連付けの場合、関連付けは一方の端からのみナビゲートできます。

したがって、単方向の@ManyToOne関連付けの場合、外部キーが存在する子側からのみ関係にアクセスできることを意味します。

単方向の@OneToMany関連付けがある場合、外部キーが存在する親側からのみ関係にアクセスできることを意味します。

双方向の@OneToManyアソシエーションの場合、親側または子側からの両方の方法でアソシエーションをナビゲートできます。

また、 双方向の関連付けにユーティリティメソッドの追加/削除を使用して、両側が適切に同期されていることを確認する も必要です。

性能

2番目の側面はパフォーマンスに関連しています。

  1. @OneToManyの場合、 単方向の関連付けは双方向のものと同様に機能しません
  2. @OneToOneの場合、 Hibernateがプロキシを割り当てる必要があるか、null値を認識できない場合、双方向の関連付けにより親が積極的にフェッチされます
  3. @ManyToManyの場合、 コレクションタイプは、SetsListsよりもパフォーマンスが高いため、かなり違いがあります
18
Vlad Mihalcea

コーディングの点では、アプリケーションはJPA仕様5(42ページ)に従って両側の同期を維持する責任があるため、双方向関係の実装はより複雑です。残念ながら、仕様で示されている例では詳細が示されていないため、複雑さのレベルはわかりません。

2次キャッシュを使用しない場合、トランザクションの終了時にインスタンスが破棄されるため、通常、リレーションシップメソッドが正しく実装されていなくても問題ありません。

2次キャッシュを使用する場合、リレーションシップ処理メソッドが誤って実装されているために何かが破損した場合、これは他のトランザクションでも破損した要素を見ることを意味します(2次キャッシュはグローバルです)。

正しく実装された双方向の関係は、クエリとコードを簡単にすることができますが、ビジネスロジックの観点から意味をなさない場合は使用しないでください。

私はこれがonlyの違いであると100%確信していませんが、main違い。また、Hibernate docsによる双方向の関連付けを持つことをお勧めします。

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

具体的には:

双方向の関連付けを優先:単方向の関連付けは、クエリがより困難です。大規模なアプリケーションでは、ほとんどすべてのアソシエーションがクエリで双方向にナビゲート可能でなければなりません。

私は個人的に、この全面的な推奨事項にわずかな問題があります-子供には親について知る実用的な理由がない場合があるようです(例えば、なぜ注文項目needそれが関連付けられている順序について知る必要がありますか?)、しかし、私はそれに時間の合理的な部分でも価値を見ます。そして、双方向性は実際には何も傷つけないので、それを順守するのはあまり好ましくないとは思いません。

9
kvista