映射(Mapping)之一对多
一对多可能是我们用得最多的数据关系了。我们还来看一对例子,有两个表分别是Order(订单)、OrderItem(订单明细)。我们一般在Order中记录该订单是开给哪个客户(Custom)的,哪天开出,过期日等信息;OrderItem则记录订单分别有哪些产品,各产品的单价、数量等明细信息。一个Order有多条OrderItem,这就是一对多。
其实Custom对Order是一对多的关系;OrderItem对Product是一对一的关系。在这里,为了方便观察,实体代码中对于涉及Custom、Product的部分作了简化,先看看对应两表的类COrder、COrderItem的简化后的代码。
public class COrder
{
// ID的私有变量
private int mID;
// Customer_ID的私有变量
private int mCustomer_ID;
// BuildDate的私有变量
private System.DateTime mBuildDate;
//
private Iesi.Collections.ISet mItems = new Iesi.Collections.HashedSet();
/// <summary>
/// 构造函数
/// </summary>
public COrder()
{
}
/// <summary>
/// 获取、设置ID
/// </summary>
public int ID
{
get
{
return this.mID;
}
set
{
this.mID = value;
}
}
/// <summary>
/// 获取、设置Customer_ID
/// </summary>
public int Customer_ID
{
get
{
return this.mCustomer_ID;
}
set
{
this.mCustomer_ID = value;
}
}
/// <summary>
/// 获取、设置BuildDate
/// </summary>
public System.DateTime BuildDate
{
get
{
return this.mBuildDate;
}
set
{
this.mBuildDate = value;
}
}

/// <summary>
/// 获取 订单的明细
/// </summary>
public Iesi.Collections.ISet Items
{
get{return this.mItems;}
set{this.mItems = value;}
}

/// <summary>
/// 添加到明细中
/// </summary>
/// <param name="pItem"></param>
public void AddItem(COrderItem pItem)
{
pItem.Order = this;
this.mItems.Add(pItem);
}
}为了方便,COrder添加一个AddItem方法来同时为COrderItem的Order成员赋值;但并没有处理Items.Add(Object obj)时COrderItem的Order成员赋值问题。请大家注意,使用后者时,测试代码需要手动赋值。
public class COrderItem
{
// ID的私有变量
private int mID;
// Price的私有变量
private System.Decimal mPrice;
// Quantity的私有变量
private System.Decimal mQuantity;
// Order_ID的私有变量
// private int mOrder_ID;
// Product_ID的私有变量
private int mProduct_ID;
/// <summary>
/// 构造函数
/// </summary>
public COrderItem()
{
}
/// <summary>
/// 获取、设置ID
/// </summary>
public int OrderItem_ID
{
get
{
return this.mID;
}
set
{
this.mID = value;
}
}
/// <summary>
/// 获取、设置Price
/// </summary>
public System.Decimal Price
{
get
{
return this.mPrice;
}
set
{
this.mPrice = value;
}
}
/// <summary>
/// 获取、设置Quantity
/// </summary>
public System.Decimal Quantity
{
get
{
return this.mQuantity;
}
set
{
this.mQuantity = value;
}
}
private COrder mOrder;

/// <summary>
/// 设置、获取 明细所属的订单
/// </summary>
public COrder Order
{
get
{
return this.mOrder;
}
set
{
this.mOrder = value;
}
}

/// <summary>
/// 获取、设置Product_ID
/// </summary>
public int Product_ID
{
get
{
return this.mProduct_ID;
}
set
{
this.mProduct_ID = value;
}
}
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="EnPrint.DB.COrderItem,EnPrint.DB" table="OrderItem">
<id name="OrderItem_ID" column="OrderItem_ID" type="Int32">
<generator class="identity" />
</id>
<property name="Price" column="Price" type="Decimal" />
<property name="Quantity" column="Quantity" type="Decimal" />
<many-to-one name="Order" column="Order_ID" class="EnPrint.DB.COrder,EnPrint.DB" unique="true"/>
<property name="Product_ID" column="Product_ID" type="Int32" />
</class>
</hibernate-mapping>
COrder order = new COrder();
order.BuildDate = DateTime.Now;
order.Customer_ID = 1;//测试简化

COrderItem item1 = new COrderItem();
item1.Price = 2.33m;
item1.Quantity = 4m;
COrderItem item2 = new COrderItem();
item2.Price = 3.34m;
item2.Quantity = 5.5m;

order.AddItem(item1);
order.AddItem(item2);

// Tell NHibernate that this object should be saved
session.Save(order);

// commit all of the changes to the DB and close the ISession
transaction.Commit();
session.Close();
NHibernate :INSERT INTO [Order] (Customer_ID, BuildDate) VALUES (?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO OrderItem (Price, Quantity, Product_ID, Order_ID) VALUES (?, ?, ?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO OrderItem (Price, Quantity, Product_ID, Order_ID) VALUES (?, ?, ?, ?)
NHibernate :SELECT @@IDENTITY
其实Custom对Order是一对多的关系;OrderItem对Product是一对一的关系。在这里,为了方便观察,实体代码中对于涉及Custom、Product的部分作了简化,先看看对应两表的类COrder、COrderItem的简化后的代码。
public class COrder
{
// ID的私有变量
private int mID;
// Customer_ID的私有变量
private int mCustomer_ID;
// BuildDate的私有变量
private System.DateTime mBuildDate;
//
private Iesi.Collections.ISet mItems = new Iesi.Collections.HashedSet();
/// <summary>
/// 构造函数
/// </summary>
public COrder()
{
}
/// <summary>
/// 获取、设置ID
/// </summary>
public int ID
{
get
{
return this.mID;
}
set
{
this.mID = value;
}
}
/// <summary>
/// 获取、设置Customer_ID
/// </summary>
public int Customer_ID
{
get
{
return this.mCustomer_ID;
}
set
{
this.mCustomer_ID = value;
}
}
/// <summary>
/// 获取、设置BuildDate
/// </summary>
public System.DateTime BuildDate
{
get
{
return this.mBuildDate;
}
set
{
this.mBuildDate = value;
}
}
/// <summary>
/// 获取 订单的明细
/// </summary>
public Iesi.Collections.ISet Items
{
get{return this.mItems;}
set{this.mItems = value;}
}
/// <summary>
/// 添加到明细中
/// </summary>
/// <param name="pItem"></param>
public void AddItem(COrderItem pItem)
{
pItem.Order = this;
this.mItems.Add(pItem);
}
}
public class COrderItem
{
// ID的私有变量
private int mID;
// Price的私有变量
private System.Decimal mPrice;
// Quantity的私有变量
private System.Decimal mQuantity;
// Order_ID的私有变量
// private int mOrder_ID;
// Product_ID的私有变量
private int mProduct_ID;
/// <summary>
/// 构造函数
/// </summary>
public COrderItem()
{
}
/// <summary>
/// 获取、设置ID
/// </summary>
public int OrderItem_ID
{
get
{
return this.mID;
}
set
{
this.mID = value;
}
}
/// <summary>
/// 获取、设置Price
/// </summary>
public System.Decimal Price
{
get
{
return this.mPrice;
}
set
{
this.mPrice = value;
}
}
/// <summary>
/// 获取、设置Quantity
/// </summary>
public System.Decimal Quantity
{
get
{
return this.mQuantity;
}
set
{
this.mQuantity = value;
}
}
private COrder mOrder;
/// <summary>
/// 设置、获取 明细所属的订单
/// </summary>
public COrder Order
{
get
{
return this.mOrder;
}
set
{
this.mOrder = value;
}
}
/// <summary>
/// 获取、设置Product_ID
/// </summary>
public int Product_ID
{
get
{
return this.mProduct_ID;
}
set
{
this.mProduct_ID = value;
}
}
} 简化后的映射配置文件
order.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="EnPrint.DB.COrder,EnPrint.DB" table="[Order]">
<id name="ID" column="ID" type="Int32">
<generator class="identity" />
</id>
<property name="Customer_ID" column="Customer_ID" type="Int32" />
<property name="BuildDate" column="BuildDate" type="DateTime" />
<set name="Items" inverse="true" lazy="true" order-by="OrderItem_ID" cascade="all">
<key column="Order_ID" />
<one-to-many class="EnPrint.DB.COrderItem, EnPrint.DB" />
</set>
</class>
</hibernate-mapping>
orderItem.hbm.xml
<class name="EnPrint.DB.COrder,EnPrint.DB" table="[Order]">
<id name="ID" column="ID" type="Int32">
<generator class="identity" />
</id>
<property name="Customer_ID" column="Customer_ID" type="Int32" />
<property name="BuildDate" column="BuildDate" type="DateTime" />
<set name="Items" inverse="true" lazy="true" order-by="OrderItem_ID" cascade="all">
<key column="Order_ID" />
<one-to-many class="EnPrint.DB.COrderItem, EnPrint.DB" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="EnPrint.DB.COrderItem,EnPrint.DB" table="OrderItem">
<id name="OrderItem_ID" column="OrderItem_ID" type="Int32">
<generator class="identity" />
</id>
<property name="Price" column="Price" type="Decimal" />
<property name="Quantity" column="Quantity" type="Decimal" />
<many-to-one name="Order" column="Order_ID" class="EnPrint.DB.COrder,EnPrint.DB" unique="true"/>
<property name="Product_ID" column="Product_ID" type="Int32" />
</class>
</hibernate-mapping>为了便于区分,OrderItem的主键没有使用我习惯使用的ID作为主键,以清楚说明one-to-many的写法。
另外COrder中Items成员使用ISet接口,于是映射文件才能象大多的示例一样
<set name.....></set>
使用ISet接口在数据绑定到控件时难免有些麻烦,我一般使用Sysetm.Collections.IList,于是映射文件中我们需要这样来定义
<bag name....></bag>
以下是nUnit的部分测试代码
COrder order = new COrder();
order.BuildDate = DateTime.Now;
order.Customer_ID = 1;//测试简化
COrderItem item1 = new COrderItem();
item1.Price = 2.33m;
item1.Quantity = 4m;
COrderItem item2 = new COrderItem();
item2.Price = 3.34m;
item2.Quantity = 5.5m;
order.AddItem(item1);
order.AddItem(item2);
// Tell NHibernate that this object should be saved
session.Save(order);
// commit all of the changes to the DB and close the ISession
transaction.Commit();
session.Close();
item1、item2不用保存?不,在保存order时,他们也会被同时保存起来。当然,实际应用需要捕捉一下保存可能出现的错误信息,以便回滚。以下是上面的测试代码将会执行的数据操作:
NHibernate :INSERT INTO [Order] (Customer_ID, BuildDate) VALUES (?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO OrderItem (Price, Quantity, Product_ID, Order_ID) VALUES (?, ?, ?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO OrderItem (Price, Quantity, Product_ID, Order_ID) VALUES (?, ?, ?, ?)
NHibernate :SELECT @@IDENTITY
注:文章所使用的C+表名来作为类名的命名规则在生成表时会有问题。
http://kevin-Y.cnblogs.com/archive/2006/01/12/315716.html


浙公网安备 33010602011771号