NHibernate-コレクションマッピング
この章では、コレクションを表現する方法について説明します。NHibernate内で使用できるコレクションには、次のようなさまざまなタイプがあります。
- Lists
- Sets
- Bags
現在、.NETの観点からは、通常、リストなど、非常に単純なデータ構造、リスト、辞書を扱います。.NETには、多種多様なコレクションタイプはありません。では、なぜNHibernateはこれらすべての異なるタイプを必要とするのでしょうか?それは本当にデータベースに戻ってきます。
リスト
リストは、必ずしも一意ではない要素の順序付けられたコレクションです。
これを使用してマッピングできます IList <T>。
したがって、従来はアドレスのリストがあり、アプリケーションの観点からは要素が一意であることがわかっていますが、リスト内に重複する要素をそのリストに挿入することを妨げるものはありません。
セットする
セットは、一意の要素の順序付けられていないコレクションです。2つの重複する要素をセットに挿入しようとすると、例外がスローされます。
NHibernateにはそれについて具体的なことは何もありません。
これは、一般的なセットの実装を行うための便利な方法です。.NET 4を使用している場合は、新しいHashSet <T> これらを表すために、しかしほとんどのNHibernateアプリケーションでは、これがISetであることを表します。
これは順序付けされていません。データベースから住所のリストまたは注文のリストをプルバックすると、特定のOrder by句を指定しない限り、住所の順番がわかりません。
したがって、一般的に、データベースからプルバックするデータはセットです。
それらは、順序付けられていない要素のユニークなコレクションです。
バッグ
データベースの世界で見られるもう1つの一般的なコレクションはバッグです。これは、重複する要素を持つことができることを除けば、セットと同じです。
.NETの世界では、これをIListで表します。
セットがおそらく最も一般的ですが、アプリケーションに応じてリストやバッグも表示されます。以下を見てみましょう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>
ご覧のとおり、注文コレクションをセットとしてマッピングしました。セットは、一意の要素の順序付けられていないコレクションであることを忘れないでください。
ここで、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...