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


135

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

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

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

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


7
これで、グループに含まれるユーザーがわかります。これは決して小さな違いではないと思います。
Satadru Biswas

5
更新に関しては、双方向の関係が私にとって混乱になりました。:)
diyoda_ 2014年

回答:


152

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

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

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

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

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

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


こんにちは、ありがとうございます。私の質問に答えているので、あなたは休止状態のエキスパートであるようです:stackoverflow.com/questions/5350770/…。私はそれをここに投稿して、私は、コメントではより多くの書き込みができないため、そして今、私は、確かな関係の保持はないです dpaste.de/J85m。可能ならばしなさいチェックを持っている:)
hguser

@hguser:最終的に双方向の関係にすることにした場合は、双方の一貫性を保つためにsetGroup()から呼び出すほうがよいと思いますaddUser()
axtavt

group.addUser()内でsetGroup()を呼び出さない場合はどうでしょうか?
hguser 2011年

@hguser:関係は持続されません。回答のポイント2を参照してください。setGroup()なしaddUser()で呼び出すこともできますが、メモリ内のオブジェクトの状態に一貫性がなくなります。
axtavt

私は正しいマッピングができないことがわかりました、githubで私のプロジェクトをチェックするために時間を割いてもらえますか?それは小さなプロジェクトです。
hguser 2011年

31

主な違いは2つあります。

協会側へのアクセス

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

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

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

双方向の@OneToMany関連付けの場合、親または子側のどちらからでも、関連付けをナビゲートできます。

また、双方向の関連付けにadd / removeユーティリティメソッド使用して、両側が適切に同期されるようにする必要もあります

パフォーマンス

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

  1. の場合@OneToMany単方向の関連付けは双方向の関連付けほど機能しません
  2. の場合@OneToOne双方向の関連付けにより、Hibernateがプロキシを割り当てる必要があるかどうか、またはnull値を通知できない場合、親が熱心にフェッチされます
  3. の場合@ManyToManyコレクション型は、Setsよりもパフォーマンスが良いListsため、かなりの違いがあります

11

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

2次キャッシュを使用しない場合、トランザクションの最後にインスタンスが破棄されるため、関係メソッドが正しく実装されていなくても問題はありません。

2次キャッシュを使用する場合、実装された関係処理メソッドが原因で何かが破損した場合、これは他のトランザクションも破損した要素を参照することを意味します(2次キャッシュはグローバルです)。

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


9

これが唯一の違いかどうかは100%わかりませんが、それが主な違いです。Hibernate docsによる双方向の関連付けも推奨されます。

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

具体的には:

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

私は個人的にこの包括的な推奨に少し問題があります-私には子供が親について知る実用的な理由がない場合があるようです(たとえば、注文アイテム注文について知っている必要があるのはなぜですか)関連付けられていますか?)、しかし私はそれに価値のある時間の部分を同様に見ます。また、双方向性が何も害を及ぼすことはないので、これを厳守するのに不快すぎるとは思いません。


axtavtが説明しているように、双方向性は場合によっては害を及ぼす可能性があります!Hibernateエンティティにマッピングされたすべてのリレーションに注意を払います。何をしているのか正確に知らない限り、Hibernateに物をロードするのに無限の時間が必要になる可能性があります。ユースケースを慎重に検討し、さまざまなユースケースに対してさまざまなモデルクラスを使用します。F.ex. 物事のリストでは、すべての関連オブジェクトは必要ありません。ラベルとIDだけが必要です。したがって、リストエンティティは、詳細エンティティとは異なる(そして非常に単純な)エンティティです。
cslotty
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.