七、NHibernate关系之——一对多

一对多关系?

在数据库中,表与表之间的关系有一对一、一对多和多对多三种,他们是关系数据库最重要的表现之所在,如果丢失了表间的关系,那么一个数据库中的数据就只是一堆没有意义的符号。NHibernate不仅可以反映实体和表的对应关系,而且可以反映表与表之间的这些关联关系。如下图:

我们在之前建立的数据模型中,包含两个表,一个是Customer表,另一个是Order表,其中Order表的外键Customer指向Customer表的主键,而Order表又有自己的主键,所以Order表对Customer表是N:1的关系,即多个Order可以属于一个Customer,一个Customer可以拥有多个Order。

一、编写Order表对应的实体类和hbm映射文件?

Order.cs如下:

namespace Model.Entities{ public class Order { public virtual Int32 OrderId { get; set; } public virtual DateTime OrderDate { get; set; } public virtual Int32 Customer { get; set; } }}

Order.hbm.xml如下:

<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″ assembly=”Model” namespace=”Model.Entities”> <class name=”Model.Entities.Order,Model” table=”[Order]”> <id name=”OrderId” column=”OrderId” type=”Int32″ unsaved-value=”0″> <generator class=”native”/> </id> <property name=”OrderDate” column =”OrderDate” type=”DateTime” not-null=”false”></property> <property name=”Customer” column=”Customer” type=”Int32″ not-null=”false”></property> </class></hibernate-mapping>

二、修改Customer表对应的实体类和hbm映射文件?

Customer.cs如下:

namespace Model.Entities{ //注意,实体类必须为public,否则无法访问 public class Customer { //在NHibernate的实体类中,所有的公共方法、属性和事件都必须使用virtual修饰 public virtual int CustomerId { get; set; } public virtual string Firstname { get; set; } public virtual string Lastname { get; set; } //一个Customer有多个Order public virtual ISet<Order> Orders { get; set; } }}

Customer.hbm.xml如下:

<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″ assembly=”Model” namespace=”Model.Entities”> <class name=”Model.Entities.Customer,Model” table=”Customer”> <!—主键,generator为自增长–> <id name=”CustomerId” column=”CustomerId” type=”Int32″ unsaved-value=”0″> <generator class=”native”></generator> </id> <!—各个字段–> <property name=”Firstname” column=”Firstname” type=”string” length=”50″ not-null=”false”></property> <property name=”Lastname” column=”Lastname” type=”string” length=”50″ not-null=”false”></property> <!–一个Customer对应多个order–> <set name=”Orders” table=”Order” generic=”true” inverse=”true”> <key column=”Customer” foreign-key=”FK_CustomerOrders”/> <one-to-many class=”Model.Entities.Order,Model”/> </set> </class></hibernate-mapping>

三、修改Order表对应的实体类和hbm映射文件?

Order.cs如下:

namespace Model.Entities{ public class Order { public virtual Int32 OrderId { get; set; } public virtual DateTime OrderDate { get; set; } //public virtual Int32 Customer { get; set; } //请注销掉Customer属性 //一个order是属于一个customer的 public virtual Customer Customer { get; set; } }}

Order.hbm.xml如下:

<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″ assembly=”Model” namespace=”Model.Entities”> <class name=”Model.Entities.Order,Model” table=”Order”> <id name=”OrderId” column=”OrderId” type=”Int32″ unsaved-value=”0″> <generator class=”native”/> </id> <property name=”OrderDate” column =”OrderDate” type=”DateTime” not-null=”false”></property> <!–同样请注释掉Customer属性–> <!–<property name=”Customer” column=”Customer” type=”Int32″ not-null=”false”></property>–> <!–一个order属于一个Customer–> <many-to-one name=”Customer” column=”Customer” not-null=”true” class=”Model.Entities.Customer,Model” foreign-key=”FK_CustomerOrders”/> </class></hibernate-mapping>

四、为两个表添加关联数据?

请添加相关联的测试数据,如下:

数据可以根据自己的喜好添加,只要关系对了就行。

五、编写DAL(数据访问层、持久层)方法来关联查询Customer和Order表?

方法可以放在旧有的文件里面,也可以放在新建的文件里面,具体参考前面的DAL层的相关文件,代码如下:

//关联查询——一对多 public IList<Customer> GetCustomersWithOrders(DateTime { IList<Customer> customers = null; //用sql查询 //customers = session // .CreateSQLQuery(“select distinct customer.* from Customer customer inner join [Order] o on o.Customer=customer.CustomerId”) // .AddEntity(“customer”, typeof(Customer)) //设置返回的值类型 // .List<Customer>(); //用HQL查询 customers = session .CreateQuery(“select distinct c from Customer c inner join c.Orders o where o.OrderDate<=:orderDate”) .SetDateTime(“orderDate”,orderDate) .List<Customer>(); return }

注意:上面的方法中提供了两种查询方式,一种是SQL查询、一种是HQL查询,当你使用其中一种时,请注释掉另外一种,以确保测试的准确性;

六、编写DAL.Test项目中的测试方法?

方法可以放在旧有的文件里面,也可以放在新建的文件里面,具体参考前面的DAL.Test层的相关文件,代码如下:

[Test] public void { IList<Customer> customers = sample.GetCustomersWithOrders(DateTime.Now); }

然后右键点击该方法,执行run test(s)命令,………………………………………………………执行成功了吗?如果成功了,真是恭喜你,你可以去买彩票了;但是我觉得绝大部分人会失败吧,是的,我的程序报了下面的错误:

—-> System.Data.SqlClient.SqlException : 在关键字’Order’ 附近有语法错误。(错误信息很多,我只复制了关键的错误信息)

这是什么原因呢?你把NHibernate生成的SQL语句Copy到查询分析器一执行就知道了,“Order”是SQL的关键字,所以报错,在查询分析器要解决这个问题就给Order加上[],一查ok;在NHibernate中也是同样的解决方法,我们将映射文件中的所有table=”Order”改成table=”[Order]”就ok了,你再测试一下看看,下面是我的测试结果:

—— Test started: Assembly: DAL.Test.dll —— NHibernate: select distinct customer0_.CustomerId as CustomerId3_, customer0_.Firstname as Firstname3_, customer0_.Lastname as Lastname3_ from Customer customer0_ inner join [Order] orders1_ on customer0_.CustomerId=orders1_.Customer where orders1_.OrderDate<=@p0;@p0 = 2009-10-18 16:45:12 1 passed, 0 failed, 0 skipped, took 5.17 seconds (NUnit 2.5.1).

天下无难事,只怕有心人。

七、NHibernate关系之——一对多

相关文章:

你感兴趣的文章:

标签云: