Nhibernate-collection-mapping
NHibernate-コレクションマッピング
この章では、コレクションを表す方法について説明します。 次のようなNHibernate内で使用できるさまざまなタイプのコレクションがあります-
- リスト
- Sets
- Bags
現在、.NETの観点からは、一般的にリストなど、非常に単純なデータ構造、リスト、辞書を扱います。 .NETには、さまざまなコレクションタイプがありません。 それでは、なぜNHibernateはこれらすべての異なるタイプを必要としますか? 本当にデータベースに戻ります。
List
- リストは、必ずしも一意ではない要素の順序付きコレクションです。
- IList <T> を使用してこれをマッピングできます。
- したがって、従来はアドレスのリストがあり、アプリケーションの観点からは要素が一意であることはわかっていますが、リストには重複した要素をリストに挿入することを妨げるものはありません。
Set
- セットは、一意の要素の順序付けられていないコレクションです。 2つの重複する要素をセットに挿入しようとすると、例外がスローされます。
- NHibernateにはそれについて特別なことは何もありません。
- これは、汎用セットを実装する便利な方法です。 .NET 4を使用している場合は、新しい HashSet <T> を使用してこれらを表すことができますが、ほとんどのNHibernateアプリケーションでは、これをISetと表します。
- 順序付けされていないため、データベースからアドレスのリストまたは順序のリストを引き戻した場合、特定のOrder by句を指定しない限り、アドレスの順序はわかりません。
- したがって、一般的に、データベースからプルバックするデータはセットです。
- これらは、順序付けられていない要素の一意のコレクションです。
Bag
- データベースの世界で見られるもう1つの一般的なコレクションはバッグです。これは、重複する要素を持つことができる点を除いて、セットに似ています。
- .NETの世界では、これをIListで表します。
セットはおそらく最も一般的ですが、アプリケーションに応じてリストとバッグも表示されます。 Set順序が定義されている最後の章の customer.hbm.xml ファイルを見てみましょう。
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
ご覧のとおり、ordersコレクションをセットとしてマップしました。 セットは一意の要素の順不同のコレクションであることを忘れないでください。
これで、Customerクラスを見ると、次のプログラムに示すように、OrdersプロパティがISetで定義されていることがわかります。
public virtual ISet<Order> Orders { get; set; }
このアプリケーションを実行すると、次の出力が表示されます。
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
Press <ENTER> to exit...
コレクション内のアイテムが一意である必要がない場合、このコレクション内で同じプライマリキーを持つ複数の注文が複数回発生する可能性がある場合、次のプログラムに示すように、これをバッグとしてマッピングする方が適切です。
<bag name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</bag>
このアプリケーションを実行すると、例外が発生します。顧客クラスを見ると、注文がC#コードでISetとしてマークされていることに気付くでしょう。
したがって、これをIListに変更する必要があります。次に、コンストラクターでHashSetからListに変更する必要があります。
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow;
Orders = new List<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual IList<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
アプリケーションを実行すると、同じ動作が見られます。 しかし、同じコレクション内で複数回注文を行うことができます。
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
Press <ENTER> to exit...