2012-10-27 7 views
15

私は2つのエンティティUSERとNOTIFICATIONがあるとします。そして私は以下のような関係を持っています。JPA OneToMany:List vs Set

public class UserAccount{ 

    @Id 
    @Column(name = "USER_NAME") 
    private String emailid; 

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinTable(name = "USERS_NOTIFICATIONS", joinColumns = { @JoinColumn(name = "USER_NAME") }, inverseJoinColumns = { @JoinColumn(name = "NOTIFICATION_ID") }) 
    private List<Notification> notifications; 

    //setters, getter, equals and hashcode 
} 

私は(IDEが私のビジネスキー/主キーと生成される)のequalsとhashCodeをオーバーライドしています。最初の通知を追加すると、通常の挿入ステートメントが取得されます。しかし、同じユーザーに対してさらに追加すると、削除してから挿入します。これはログです:

Hibernate: delete from USERS_NOTIFICATIONS where USER_NAME=? 
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?) 
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?) 
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?) 
//as many inserts as the notifications the user has 

すべてのユーザーに同じことが起こります。今、ListをSetと置き換えると、通常の挿入が行われます。そして、私はdoucmentationblogを読んだ後に理由を見つけました。一方向OneToManyアソシエーションセット内のドキュメント

  • から

    観測が好ましいです。

インデックス付きコレクションとセットは要素の追加、削除、更新するという点で、最も効率的な動作を許可することは明らかです。双方向OneToMany関係(ManyToOne管理)一覧やバッグに

  • が効率的です。

バッグやリスト、最も効率的な逆のコレクションです質問

のカップルは、この平均は私が(単方向OneToManyマッピングでリスト上の設定を好む持っていますかなり明らかだけど)?しかし、回避策はありますか?

  • また、重複している場合にはリストを使用するためにドメインを調整する必要がありますか。
  • +2

    注文したいときにListを使い、そうでないときはSetを使うと思っていました。任意の永続性ソリューションに関係なく、モデル化する必要があるものに基づいてモデルを選択します。どの永続性ソリューションでもどちらかを処理できなければならない – DataNucleus

    +3

    @DataNucleus:誰もそれを考えていました。 Hibernateが単方向マップへの効率的な追加を効率的に処理するとも考えていました。ある時には、考えが間違っていることが分かりました! –

    +0

    @DataNucleas:それもそうだと思っていましたが、上記の問題を抱えてドキュメンテーションを見て、それ以上のことを見つけました。 – shazinltc

    答えて

    1

    リスト:それに重複する要素を許可します。

    設定:すべての要素は一意である必要があります。

    ここで、リスト内の要素を上書きしているために削除が行われる可能性があります。したがって、UserAccount型の永続エンティティを変更すると、リスト内に存在するエンティティが削除されます。

    +0

    いいえ。そうではありません。私が記載した文書をお読みください。それは削除の理由があります。 – shazinltc

    8

    私はこの問題に直面しませんでした...

    私はこの記事を見つけた:短期的に休止https://fedcsis.org/proceedings/2013/pliks/322.pdfの多く 協会に対する一つのパフォーマンスアンチパターン

    • バッグのセマンティクス - >List/Collection + @OneToMany - >一つの要素を追加しました:1削除、N個の挿入、削除された1個の要素:削除、N個の挿入
    • リストの意味 - >List + @OneToMany + @IndexColumn/@OrderColumn - >一つの要素を追加しました:1、挿入、Mの更新、一つの要素を削除:1削除、Mの更新
    • セットのセマンティクス - >Set + @OneToMany - >一つの要素を追加しました:1つのインサート、一つの要素が削除された:1
    削除

    私にとって:はい、単方向の場合ListSetに変更する必要があることを意味します。@OneToManyだから私はモデルをHibernateの期待に合わせて変更しました。アプリケーションのビュー部分がほとんどListに依存していたため、多くの問題が発生しました。

    一方で、Setは私にとって論理的な選択です重複はなく、一方でListは扱いが簡単でした。

    JPA/Hibernateはモデルオブジェクトを変更することを余儀なくされましたが、これは初めてではありませんでした。@EmbededIdを使用している場合、JPA/Hibernateを使用しない場合とほとんど同じことをしません。特に、等価メソッドのすべてのアプリケーションでHibernateProxyを認識しなければならないときは... else if(object instanceof HibernateProxy) { ... JPA/Hibernateのpersitenceレイヤーは他のレイヤーに少し侵入しています。

    しかし、JDBCを直接使用すると、モデルやビジネスメソッドを変更して永続性を向上させることもできます。 レイヤーの分離は、夢であるか、あまりにも多くの費用がかかりすぎますか?

    そして、彼らはいくつかのコードがListに依存していると(例えばJSF/PrimeFaces <dataTable>または<repeat>コンポーネントとして)変更することができない問題をもたらす注釈@OrderBy

    TreeSetようSortedSetある場合はSetを注文することができ だから、をListに変更してSetに戻る必要がありますが、setNotifications(new HashSet<>(notificationList))を実行すると、そのセットがHibernateによって管理されるorg.hibernate.collection.PersistentSetであるため、追加のクエリが発生します...だからaddAll()removeAll()を使用しましたセッターの代わり:

    protected <E> void updateCollection(@NonNull Collection<E> oldCollection, @NonNull Collection<E> newCollection) { 
        Collection<E> toAdd = new ArrayList<>(newCollection) ; 
        toAdd.removeAll(oldCollection) ; 
    
        Collection<E> toRemove = new ArrayList<>(oldCollection) ; 
        toRemove.removeAll(newCollection) ; 
    
        oldCollection.removeAll(toRemove) ; 
        oldCollection.addAll(toAdd) ; 
    } 
    

    マインドあなた@Entityequals()hashCode()方法...

    もう1つの問題は、Set/List/BagのセマンティクスがJPAからのHibernateであるため、Hibernateを実装としてJPAを使用する場合、JPAとHibernateの両方をマスターする必要があることです。 )

    特定のベンダーに依存しないように実装を抽象化するための仕様です。ほとんどのJavaEE仕様は成功しましたがJPAは失敗しましたが、私はHibernateから独立していました。

    +0

    ありがとう!紙は本当に悪い読書! –