4

JPA/Hibernateを使ってグループとアカウントの2つのエンティティ間の関係をモデル化したいと思います。アカウントはいくつかのグループを持つことができますが、その逆もありません。そのため、アカウントとグループの間にOneToMany関係があります。 私の作業の同僚は、私の質問はGroupのコンストラクタでのヘルパーメソッドaddToAccountの使い方について今ある 休止状態のエンティティを構築するときに双方向関係を処理する方法は?

public class Group { 
    private String name; 
    private Account account; 

    public Group() {} 

    public Group(String name, Account account) { 
     this.name = name; 
     addToAccount(account); 
    } 

    public void addToAccount(Account account) { 
     setAccount(account); 
     List<Group> accountGroups = account.getGroups(); 
     accountGroups.add(this); 
    } 

    @ManyToOne 
    public Account getAccount() { 
     return account; 
    } 

    public void setAccount(Account account) { 
     this.account = account; 
    } 
} 

public class Account { 
    private List<Group> groups = new ArrayList<Group>(); 

    public Account() {} 

    public void setGroups(List<Group> usergroups) { 
     this.groups = groups; 
    } 

    @OneToMany(mappedBy = "account") 
    public List<Group> getGroups() { 
     return groups; 
    } 
} 

のようなエンティティ AccountGroupをモデル化することが示唆されました。私の仕事の同僚によると、この方法は、2つのエンティティの一貫したメモリモデルを保証するために、両方のエンティティ間の双方向の関係を更新する必要があるため必要です。

  1. Group SのListはとてもオープン トランザクションを必要とaddToAccount方法 を呼び出し、遅延し フェッチされるので

    私はコンストラクタでメソッドaddToAccountを呼び出すと信じてしかしは、良いアイデアではありません。したがって、 Groupのコンストラクタは、 オープントランザクション内でのみ呼び出すことができます。私の意見では、これは非常に迷惑な制限です。 Groupのコンストラクタへの引数として与えられた

  2. Accountオブジェクトはコンストラクタによって を変化させます。私の意見では、これは のコンシューマーGroup の驚くべき副作用であり、起こるべきではありません。

私の提案は、より良い

public Group(String name, Account account) { 
      this.name = name; 
      this.account = account; 
     } 

のような単純なコンストラクタを使用して、手動で双方向の関係に対処することでした。しかし、多分私は間違っています。休止状態のエンティティを構築するときに双方向関係を処理する方法は共通していますか?

+0

私はそれがあなたの大学が提案していた悪い習慣だと信じています。上記のうち1つまたは2つ(特に2!)だけでなく、コンストラクタ内でオーバーライド可能なメソッドを使用する必要があります。これは、サブクラスでうまく上書きされ、子オブジェクトコンストラクタが呼び出される前に呼び出される可能性があります。私はあなたが一貫したオブジェクトグラフ(メモリモデル)を維持すべきだと私は信じています、私は今、それを最善を尽くす方法について研究しています。ようやく答えに出ますか? – Victor

答えて

0

私の経験では、よく行われているように正確にやっています。私の質問は、グループから直接アカウントを操作したい理由について、構造についての詳細です(上記のサンプルよりもさらに多くのことが起こると思います)。

これはOneToManyかManyToManyのどちらの状況でも問題です(通常、複数のアカウントは1つのグループに属し、複数のグループは1つのアカウントに属することができますが、すべて特定の会計スキームの意味になります... )とにかく:あなたはそれを正しくやっているのですが、私は(まさにこのケースで)どうしてアカウントを直接操作したいのか(なぜなら、遅延ロードされていない限り)疑問に思っています。

[それは正しく構成に応じて持続するように、あなたはいくつかのカスケードルールを追加する必要があるかもしれません。]

アカウントにマッピングすることにより、あなたが効果的にアカウントのリストに追加していることに注意してください。データベースが次にそのリストを作成するためにクエリを実行すると、アカウントエンティティからの参照を見つけることによってリストが作成されます。短期で

>

public void Group.setAccounts(Account a) 
{ 
    this.account = a; 
} 

は、あなたが上記のやっていることを効果的に等価です。リストがクエリによって定義されているグループへの追加は不要です怠惰な負荷とは別に、このよう

//Pseudo SQL 
    SELECT g.id FROM Group g WHERE g.account_id = :account_id 

(あなたがかもしれない何かをかたくない場合があります):データベースが照会しに似て何かをリストに移入されます。私たちは通常、双方向の関連付けを回避しようと私たちのプロジェクトで

(それはシンプルに見える、あまりにもハードそれをしないでください。私は長い説明があなたにJPAで何が起こっているかのアイデアを与える願っています)

3

たとえば、Accountをシリアル化したいとし、シリアル化アルゴリズムがスマートではない場合など、何らかの方法でシリアル化するには問題が発生する可能性があります。無限ループ(GroupにはAccountへの参照が戻っているため)。

2番目の理由は、モデルをナビゲートする方法が1つしかないことがわかりました。私が通常行うことは、AccountエンティティのOneToMany関連付けを削除し、特定のAccountGroupをすべて収集する必要があるときにリポジトリ呼び出しを使用することです(しかし、これはおそらくあなたのユースケースと個人的な好みに依存します)。

第3に、addToAccountメソッドを削除してフィールドアクセスを使用すると、クラスを不変にすることができますが、それは良いことです。

関連する問題