次のコレクションタイプのうち、JPAドメインモデルで使用するものとその理由:
Java.util.Collection
Java.util.List
Java.util.Set
これにはいくつかの基本的なルールがあるのかと思っていました。
[〜#〜] update [〜#〜]Set
とList
の違いを知っています。 List
は重複を許可し、順序を持ち、Set
は重複する要素を含むことができず、順序を定義しません。私はこの質問をJPAの文脈で聞いています。厳密に定義に従う場合、コレクションはリレーショナルデータベースに格納されているため、常にSet
タイプを使用する必要があります。リレーショナルデータベースでは、重複がなく、自分で順序を定義できます。あなたの順序Java List
は、必ずしもDBに保存されているわけではありません。
たとえば、ほとんどの場合、List
型を使用していますが、順序があるため、または重複が許可されているためではありません(とにかく所有できません)。コンポーネントライブラリの一部のコンポーネントにはリスト。
あなた自身の質問が示唆するように、キーはJPAではなくドメインです。 JPAは、問題に最適な方法で使用できる(そして使用する必要がある)フレームワークです。フレームワーク(またはその制限)のために次善のソリューションを選択することは、通常は警告です。
セットが必要で、順序を気にしない場合は、Set
を使用します。何らかの理由で順序が重要な場合(順序付きリスト、日付順など)、List
。
Collection
、Set
、およびList
の違いをよく知っているようです。どちらか一方を使用する唯一の理由は、ニーズのみに依存します。 それらを使用して、API(または将来の自己)のユーザーにコレクションのプロパティを伝える(微妙または暗黙的かもしれません)。
これは、コード全体で異なるコレクションタイプを使用する場合とまったく同じルールに従います。すべての参照にObject
またはCollections
を使用できますが、ほとんどの場合、より具体的な型を使用します。
たとえば、List
が表示された場合、何らかの方法でソートされていることがわかります。この場合、重複は許容されるか、無関係です。 Set
が表示された場合、通常、重複や特定の順序がないことを期待します(SortedSet
でない限り)。 Collection
が表示されたとき、エンティティが含まれていること以外は期待していません。
リストの順序について...はい、保存できます。そうでなくても、@OrderBy
、それはまだ便利です。デフォルトでタイムスタンプでソートされたイベントログの例を考えてください。リストを人為的に並べ替えるのはあまり意味がありませんが、それでもデフォルトでソートされると便利です。
セットまたはリストを使用することの質問は、私が考えるよりはるかに難しいです。少なくともhibernateをJPA実装として使用する場合。リストを休止状態で使用すると、重複するCANが存在する "Bags"パラダイムに自動的に切り替わります。
そして、その決定はhibernateが実行するクエリに大きな影響を与えます。ここに小さな例があります:
2つのエンティティ、employeeおよびcompany、典型的な多対多-多くの関係。これらのエンティティを相互にマッピングするために、JoinTable(「employeeCompany」と呼びます)が存在します。
両方のエンティティ(会社/従業員)でデータタイプリストを選択します。
したがって、removeEmployeeJoefromCompanyXY、hibernateは次のクエリを実行します。
delete from employeeCompany where employeeId = Joe;
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXA);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXB);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXC);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXD);
insert into employeeCompany(employeeId,companyId) values (Joe,CompanyXE);
そして今、質問:地獄はなぜそのクエリを実行するだけでなく休止状態になるのですか?
delete from employeeCompany where employeeId = Joe AND company = companyXY;
答えは簡単です(そして彼のブログ投稿でNirav Assarにたくさん感謝します):それはできません。バッグの世界では、すべてを削除して残りをすべて再挿入することが唯一の適切な方法です!より明確にするためにそれを読んでください。 http://assarconsulting.blogspot.fr/2009/08/why-hibernate-does-delete-all-then-re.html
今大きな結論:
従業員/会社-エンティティでリストではなくセットを選択した場合、その問題は発生せず、1つのクエリのみが実行されます!
そして、なぜですか?休止状態はもはやバッグの世界ではないので(ご存じのように、セットは重複を許可しません)、1つのクエリのみを実行できるようになりました。
したがって、少なくともクエリとパフォーマンスに関しては、リストとセットの決定はそれほど単純ではありません!
通常、リストを使用します。 List APIはSetよりもはるかに便利で、他のライブラリと互換性があると思います。リストは反復が簡単で、ほとんどの操作とメモリで一般的に効率的です。
関係に重複を持たせることはできず、通常は順序付けされていないという事実は、Setの使用を必要とするべきではありません。アプリケーションにとって最も役立つCollectionタイプを使用できます。
ただし、モデルによって異なります。多くの包含チェックを行う場合は、Setの方が効率的です。
@OrderByまたは@OrderColumnを使用して、JPAで関係を順序付けできます。
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Ordering を参照してください
JPAでは重複は通常サポートされていませんが、ElementCollectionsなどの一部のマッピングでは重複がサポートされている場合があります。
私が使う:
Netbeansでエンティティを生成するときにコレクションを一般的なデフォルトとして使用することは良い出発点であり、モデルが実際に何であるかを理解し、より多くの機能が必要な場合、簡単に変更して下位互換性を維持できます。