目录

写在前面

文档与系列文章

一对多关系

一个例子

级联删除

级联保存

总结

写在前面

在前面的文章中,我们只使用了一个Customer类进行举例,而在客户、订单、产品中它们的关系,咱们并没有涉及,比如一个客户可以有一个或者多个订单,在数据库中变现为“主外键关系”,有时也喜欢称为“父子关系”。那么就让我们一起学习,在nhibernate中,是如何处理这种关系的吧?

文档与系列文章

[Nhibernate]体系结构

[NHibernate]ISessionFactory配置

[NHibernate]持久化类(Persistent Classes)

[NHibernate]O/R Mapping基础

[NHibernate]集合类(Collections)映射 

[NHibernate]关联映射

[NHibernate]Parent/Child

[NHibernate]缓存(NHibernate.Caches)

[NHibernate]NHibernate.Tool.hbm2net

[NHibernate]Nullables

[NHibernate]Nhibernate如何映射sqlserver中image字段

[NHibernate]基本配置与测试 

[NHibernate]HQL查询 

[NHibernate]条件查询Criteria Query

[NHibernate]增删改操作

[NHibernate]事务

[NHibernate]并发控制

[NHibernate]组件之依赖对象

一对多关系

首先看一下数据表的关系。

[NHibernate]一对多关系(级联删除,级联添加)

这里先使用Customer和Order的关系为例进行说明,一个客户可以有一个或者多个订单的关系。

在nhibernate中定义了多种集合方式:

Bag:对象集合,集合中的元素可以重复。例如:{1,2,3,4,2,3},相当于.Net中的IList和IList<T>。

Set:对象集合,集合中的元素必须唯一。例如:{1,3,4},相当于.Net中的ISet和ISet<T>,nhibernate的Iesi.Collections.dll程序集提供ISet集合。

List:整数索引集合,集合中的元素可以重复。例如:{{1,"zhangsan"},{2,"lisi"}},相当于.Net中ArrayList和List集合。

Map:键值对集合,相当于.Net中的IDictionary<TKey,TValue>和Hashtable。

使用过Entity Framework的朋友都知道,在EF中使用的ISet,为了保持一直,这里也使用ISet集合,也方便以后如果使用ef的时候,用起来更顺手。

一个例子

在nhibernate-4.0版本中,在命名空间Iesi.Collections.Generic中已经没有ISet集合了,那么我们使用.net中的ISet代替来描述这种一对多的关系,Customer.cs类代码如下:

 1     /// <summary>
 2     /// 描述:客户实体,数据库持久化类
 3     /// 创建人:wolfy
 4     /// 创建时间:2014-10-16
 5     /// </summary>
 6     public class Customer
 7     {
 8         /// <summary>
 9         /// 客户id
10         /// </summary>
11         public virtual Guid CustomerID { get; set; }
12         /// <summary>
13         /// 客户名字
14         /// </summary>
15         public virtual Name NameAddress { get; set; }
16         /// <summary>
17         /// 版本控制
18         /// </summary>
19         public virtual int Version { get; set; }
20         /// <summary>
21         /// 一对多关系:一个Customer有一个或者多个Order
22         /// </summary>
23         public virtual System.Collections.Generic.ISet<Order> Orders { set; get; }
24     }

修改Order类

 1     /// <summary>
 2     /// 描述:订单实体,数据库持久化类
 3     /// 创建人:wolfy
 4     /// 创建时间:2014-10-16
 5     /// </summary>
 6     public class Order
 7     {
 8         /// <summary>
 9         /// 订单id
10         /// </summary>
11         public virtual Guid OrderID { set; get; }
12         /// <summary>
13         /// 下订单时间
14         /// </summary>
15         public virtual DateTime OrderDate { set; get; }
16         /// <summary>
17         /// 下订单的客户,多对一的关系:orders对应一个客户
18         /// </summary>
19         public virtual Customer Customer { set; get; }
20     }

在nhibernate中,可以通过映射文件来关联对象之间的关系。

  • 对象之间的关系:一对一,多对一,一对多,多对多关系。
  • 在关系中控制级联行为(Cascade behavior):级联删除,级联更新。
  •  父子关系的双向导(bidirectional navigation)

父实体映射

父实体Customer映射文件中,定义了:

集合类型:Set,Bag,List,Map

在保存,更新,删除操作时的级联行为。

关联的控制方向:

inverse=“false”(默认)父实体负责维护关联关系。

inverse=“true”子实体负责维护关联关系。

与子实体的关系:一对多,多对一,多对多。

修改Customer.hbm.xml映射文件,描述一个客户对应多个订单的关系

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <!--assembly:程序集,namespace:命名空间-->
 3 <hibernate-mapping  xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain"  namespace="Wolfy.Shop.Domain.Entities">
 4   <class name="Wolfy.Shop.Domain.Entities.Customer,Wolfy.Shop.Domain" table="TB_Customer">
 5     <!--主键-->
 6     <id name="CustomerID" type="Guid" unsaved-value="null">
 7       <column name="CustomerID" sql-type="uniqueidentifier" not-null="true" unique="true"/>
 8       <generator class="assigned"></generator>
 9     </id>
10     <!--版本控制-->
11     <version name="Version" column="Version" type="integer"  unsaved-value="0"/>
12     <!--组件 name组件属性名-->
13     <component name="NameAddress" class="Wolfy.Shop.Domain.Entities.Name,Wolfy.Shop.Domain">
14       <!--Name类中的属性property-->
15       <property name="CustomerName" column ="CustomerName" type="string"
16                            length="16" not-null="false" />
17       <property name ="CustomerAddress" column="CustomerAddress" type="string"
18                            length="128" not-null="false" />
19     </component>
20     <!--一对多关系:一个客户可以有一个或者多个订单-->
21     <!--子实体负责维护关联关系-->
22     <set name="Orders" table="TB_Order" generic="true" inverse="true">
23       <key column="CustomerID" foreign-key="FK_TB_Order_TB_Customer"></key>
24       <one-to-many class="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain"/>
25     </set>
26   </class>
27 </hibernate-mapping>

添加Order.hbm.xml映射文件

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain"  namespace="Wolfy.Shop.Domain.Entities">
 3   <class name="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain" table="TB_Order">
 4     <id name="OrderID" column="OrderID" type="Guid" unsaved-value="null">
 5       <generator class="assigned" />
 6     </id>
 7     <property name="OrderDate" column="OrderDate" type="DateTime"
 8               not-null="true" />
 9     <!--多对一关系:Orders属于一个Customer-->
10     <many-to-one  name="Customer" column="CustomerID" not-null="true" 
11                  class="Wolfy.Shop.Domain.Entities.Customer,Wolfy.Shop.Domain"
12                  foreign-key="FK_TB_Order_TB_Customer" />
13   </class>
14 </hibernate-mapping>

many-to-one节点属性介绍:

子实体(Order)映射定义:与父实体关联的(多对一、一对多、多对多) 关系,并用一个指针来导航到父实体。

在“子”端通过many-to-one元素定义与“父”端的关联,从“子”端角度看这种关系模型是多对一关联(实际上是对Customer对象的引用)。下面看看many-to-one元素映射属性:

[NHibernate]一对多关系(级联删除,级联添加)

access(默认property):可选field、property、nosetter、ClassName值。NHibernate访问属性的策略。

cascade(可选):指明哪些操作会从父对象级联到关联的对象。可选all、save-update、delete、none值。除none之外其它将使指定的操作延伸到关联的(子)对象。

class(默认通过反射得到属性类型):关联类的名字。

column(默认属性名):列名。

fetch(默认select):可选select和join值,select:用单独的查询抓取关联;join:总是用外连接抓取关联。

foreign-key:外键名称,使用SchemaExport工具生成的名称。

index:......

update,insert(默认true):指定对应的字段是否包含在用于UPDATE或INSERT 的SQL语句中。如果二者都是false,则这是一个纯粹的 “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他特性得到或者通过触发器其他程序得到。

lazy:可选false和proxy值。是否延迟,不延迟还是使用代理延迟。

name:属性名称propertyName。

not-found:可选ignore和exception值。找不到忽略或者抛出异常。

not-null:可选true和false值。

outer-join:可选auto、true、false值。

property-ref(可选):指定关联类的一个属性名称,这个属性会和外键相对应。如果没有指定,会使用对方关联类的主键。这个属性通常在遗留的数据库系统使用,可能有外键指向对方关联表的某个非主键字段(但是应该是一个唯一关键字)的情况下,是非常不好的关系模型。比如说,假设Customer类有唯一的CustomerId,它并不是主键。这一点在NHibernate源码中有了充分的体验。

unique:可选true和false值。控制NHibernate通过SchemaExport工具生成DDL的过程。

unique-key(可选):使用DDL为外键字段生成一个唯一约束。

编写OrderData.cs代码,添加Order

 1     /// <summary>
 2     /// 描述:订单数据层
 3     /// 创建人:wolfy
 4     /// 创建时间:2014-11-02
 5     /// </summary>
 6     public class OrderData
 7     {
 8         /// <summary>
 9         /// 添加订单
10         /// </summary>
11         /// <param name="order"></param>
12         /// <returns></returns>
13         public bool AddOrder(Order order)
14         {
15             try
16             {
17                 NHibernateHelper nhibernateHelper = new NHibernateHelper();
18                 var session = nhibernateHelper.GetSession();
19                 session.SaveOrUpdate(order);
20                 session.Flush();
21                 return true;
22             }
23             catch (Exception)
24             {
25                 throw;
26             }
27         }
28     }

测试页面AddCustomer.aspx

 1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CustomerManager.aspx.cs" Inherits="Wolfy.Shop.WebSite.CustomerManager" %>
 2 
 3 <!DOCTYPE html>
 4 
 5 <html xmlns="http://www.w3.org/1999/xhtml">
 6 <head runat="server">
 7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 8     <title></title>
 9     <style type="text/css">
10         .main {
11             border: 1px solid #0094ff;
12             margin: 50px auto;
13             width: 600px;
14         }
15 
16         .table {
17             border: 1px solid #0094ff;
18             border-collapse: collapse;
19             width: 98%;
20             text-align: center;
21             margin: 5px auto;
22         }
23 
24             .table th {
25                 background-color: lightgray;
26             }
27 
28             .table tr td {
29                 border: 1px solid #0094ff;
30             }
31     </style>
32 </head>
33 <body>
34     <form id="form1" runat="server">
35         <div class="main">
36             <asp:Button runat="server" ID="btnAdd" Text="添加" OnClick="btnAdd_Click" /><asp:Button Text="并发更新" ID="btnSameTimeUpdate" runat="server" OnClick="btnSameTimeUpdate_Click" /><br />
37             按姓名查询:
38             <asp:TextBox runat="server" ID="txtName" />
39             <asp:TextBox runat="server" ID="txtAddress" />
40             <asp:Button Text="查询" runat="server" ID="btnSearch" OnClick="btnSearch_Click" />
41 
42             <div>
43                 <asp:Repeater runat="server" ID="rptCustomerList">
44                     <HeaderTemplate>
45                         <table class="table">
46                             <tr>
47                                 <th>姓名</th>
48                                 <th>姓名</th>
49                                 <th>地址</th>
50                                 <th>版本</th>
51                                 <th>姓名/地址</th>
52                                 <th>操作</th>
53                             </tr>
54                     </HeaderTemplate>
55                     <ItemTemplate>
56                         <tr>
57                             <td><%#Container.ItemIndex+1 %></td>
58                             <td><%#Eval("NameAddress.CustomerName") %></td>
59                             <td><%#Eval("NameAddress.CustomerAddress") %></td>
60                             <td><%#Eval("Version") %></td>
61                             <td><%#Eval("NameAddress.NameAddress") %></td>
62                             <td>
63                                 <asp:LinkButton runat="server" ID="lnkOrder" CommandArgument='<%#Eval("CustomerID") %>' CommandName="Order"  OnClick="lnkOrder_Click">下单</asp:LinkButton></td>
64                         </tr>
65                     </ItemTemplate>
66                     <FooterTemplate>
67                         </table>
68                     </FooterTemplate>
69                 </asp:Repeater>
70             </div>
71         </div>
72     </form>
73 </body>
74 </html>
View Code

相关文章:

  • 2022-01-01
  • 2022-12-23
  • 2022-12-23
  • 2022-01-02
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-01-08
  • 2022-01-21
  • 2021-11-20
  • 2021-11-09
相关资源
相似解决方案