映射(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;
            }

        }

    }

 简化后的映射配置文件
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
<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

posted @ 2006-01-09 15:10  生命体验之kevin-Y  阅读(2397)  评论(0)    收藏  举报