[转]NHibernate之旅(11):探索多对多关系及其关联查询
本节内容
- 多对多关系引入
- 多对多映射关系
- 多对多关联查询
- 1.原生SQL关联查询
- 2.HQL关联查询
- 3.Criteria API关联查询
- 结语
多对多关系引入
让我们再次回顾在第二篇中建立的数据模型:

在图上,我已经清晰的标注了表之间的关系,上两篇分析Customer和Order之间的“外键关系”或者称作“父子关系”、“一对多关系”和关联查询,这一篇以Order为中心,分析Order和Product之间的关系,直接看下面一幅图的两张表:

上面两张表关系表达的意思是:Order有多个Products,Product属于多个Orders。我们称Order和Product是多对多关系,这一篇我们来深入讨论在NHibernate如何映射多对多关系及其多对多关联查询。
多对多映射关系
1.Order有多个Products
有了上两篇的基础,现在直奔主题,建立关系。大家可以把这篇的代码作为模板,以后在工作中参考。
修改Order.cs类代码如下:
namespace DomainModel.Entities
{
public class Order
{
public virtual int OrderId { get; set; }
public virtual DateTime OrderDate { get; set; }
//多对一关系:Orders属于一个Customer
public virtual Customer Customer { get; set; }
//多对多关系:Order有多个Products
public virtual IList<Product> Products { get; set; }
}
}
修改Order.hbm.xml映射文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="DomainModel" namespace="DomainModel"> <class name="DomainModel.Entities.Order,DomainModel" 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="true" />
<!--多对一关系:Orders属于一个Customer-->
<many-to-one name="Customer" column="Customer" not-null="true"
class="DomainModel.Entities.Customer,DomainModel"
foreign-key="FK_CustomerOrders" />
<!--多对多关系:Order有多个Products-->
<bag name="Products" generic="true" table="OrderProduct">
<key column="`Order`" foreign-key="FK_OrderProducts"/>
<many-to-many column="Product"
class ="DomainModel.Entities.Product,DomainModel"
foreign-key="FK_ProductOrders"/>
</bag>
</class>
</hibernate-mapping>
在多对多关系中,其两方都使用Bag集合和many-to-many元素。看看上面各个属性和one-to-many,many-to-one属性差不多。
2.Product属于多个Orders
在项目DomainModel层的Entities文件夹中新建Product.cs类,编写代码如下:
namespace DomainModel.Entities
{
public class Product
{
public virtual int ProductId { get; set; }
public virtual string Name { get; set; }
public virtual float Cost { get; set; }
//多对多关系:Product属于多个Orders
public virtual IList<Order> Orders { get; set; }
}
}
在项目DomainModel层的Mappings文件夹中新建Product.hbm.xml映射文件,编写代码如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="DomainModel" namespace="DomainModel">
<class name="DomainModel.Entities.Product,DomainModel" table="Product"> <id name="ProductId" column ="ProductId" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property name="Name" column="Name" type="string" not-null="true" length="50"/>
<property name="Cost" column="Cost" type="float" not-null="true"/>
<!--多对多关系:Product属于多个Orders-->
<bag name="Orders" generic="true" table="OrderProduct">
<key column="Product" foreign-key="FK_ProductOrders"/>
<many-to-many column="`Order`"
class="DomainModel.Entities.Order,DomainModel"
foreign-key="FK_OrderProducts"/>
</bag>
</class>
</hibernate-mapping>
多对多关联查询
使用NHibernate中提供的三种查询方法实现多对多关联查询,查询返回所有订单和产品的顾客列表。
1.原生SQL关联查询
public IList<Customer> UseSQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
{
return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}" +
" inner join [Order] o on o.Customer={customer}.CustomerId"+
" inner join OrderProduct op on o.OrderId=op.[Order]"+
" inner join Product p on op.Product=p.ProductId where o.OrderDate> :orderDate")
.AddEntity("customer", typeof(Customer))
.SetDateTime("orderDate", orderDate)
.List<Customer>();
}
这里需要使用Join告诉查询如何在表之间关联。无论多么复杂的关系,我们必须在查询语句中指定返回值。这里使用AddEntity设置返回的实体。
2.HQL关联查询
public IList<Customer> UseHQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
{
return _session.CreateQuery("select distinct c from Customer c ,"
+ " c.Orders.elements o where o.OrderDate > :orderDate")
.SetDateTime("orderDate", orderDate)
.List<Customer>();
}
因为在映射文件已经定义实体之间一对多、多对多关系,NHibernate通过映射文件知道如何去关联这些实体,我们不需要在查询语句中重复定义。这里使用查询和上一篇使用HQL关联查询语句一样,NHibernate完全可以去关联对象,实现查询订单和产品。
3.Criteria API关联查询
因为实体之间的关联我们在映射文件中已经定义好了。所以我们在查询子对象使用子CreateCriteria语句关联对象之间导航,可以很容易地在实体之间指定约束。这里第二个CreateCriteria()返回ICriteria的新实例,并指向Orders实体的元素。第三个指向Products实体的元素。
public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()
{
return _session.CreateCriteria(typeof(Customer))
.Add(Restrictions.Eq("Firstname","YJing"))
.CreateCriteria("Orders")
.Add(Restrictions.Gt("OrderDate",new DateTime(2008,10,1)))
.CreateCriteria("Products")
.Add(Restrictions.Eq("Name","Cnblogs"))
.List<Customer>();
}
下面我用一幅图简单明了的说明这段代码神秘之处,也显示了一些约束条件。

编写一个测试用例测试UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()方法,遍历列表,看看产品名称是否为“Cnblogs”,OK!测试通过。
[Test]
public void UseCriteriaAPI_GetCustomerswithOrdersHavingProductTest()
{
IList<Customer> customers = _relation.UseCriteriaAPI_GetCustomerswithOrdersHavingProduct();
bool found = false;
foreach (Customer c in customers)
{
foreach (Order o in c.Orders)
{
foreach (Product p in o.Products)
{
if (p.Name == "Cnblogs")
{
found = true;
break;
}
}
}
}
Assert.IsTrue(found);
}
下面再写个简单例子查询产品Id所关联的一些顾客,测试用例同上面差不多,自己修改下就可以啦。
public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct(int productId)
{
return _session.CreateCriteria(typeof(Customer))
.CreateCriteria("Orders")
.CreateCriteria("Products")
.Add(Restrictions.Eq("ProductId", productId))
.List<Customer>();
}
结语
这一篇通过全盘代码的形式完成NHibernate中的多对多关系映射,使用NHibernate中提供的三种查询方法实现了多对多关联查询。希望对你有所帮助,多多练习。我们下次继续讨论NHibernate话题,像延迟加载、立即加载、对象状态等话题,关于朋友回复说讨论更多话题,我只能说,再等等吧,慢慢来,这才第十一篇,先把基础的问题弄清楚。
[转]NHibernate之旅(11):探索多对多关系及其关联查询的更多相关文章
- [NHibernate]多对多关系(关联查询)
目录 写在前面 文档与系列文章 多对多关系关联查询 总结 写在前面 上篇文章介绍了nhibernate中对一对多关系进行关联查询的几种方式,以及在使用过程需要注意的问题.这篇文章对多对多关系的查询处理 ...
- [NHibernate]一对多关系(关联查询)
目录 写在前面 文档与系列文章 一对多查询 总结 写在前面 上篇文章介绍了nhibernate的一对多关系如何配置,以及级联删除,级联添加数据的内容.这篇文章我们将学习nhibernate中的一对多关 ...
- 用NHibernate处理带属性的多对多关系
1.引言 老谭在面试开发者的时候,为了考察他们的数据库开发能力,经常祭出我的法宝,就是大学数据库教程中讲到的一个模式:学生选课.这个模式是这种: 在这个模式中,学生(Student)和课程(Cours ...
- NHibernate之旅系列文章导航
NHibernate之旅系列文章导航 宣传语 NHibernate.NHibernate教程.NHibernate入门.NHibernate下载.NHibernate教程中文版.NHibernate实 ...
- NHibernate教程(11)--多对多关联查询
本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...
- [转]NHibernate之旅(9):探索父子关系(一对多关系)
本节内容 引入 NHibernate中的集合类型 建立父子关系 父子关联映射 结语 引入 通过前几篇文章的介绍,基本上了解了NHibernate,但是在NHibernate中映射关系是NHiberna ...
- mybatis多表查询之多对多关系查询的实现-xml方式
Mybatis对于多对多关系下的查询提供了集合(collection)的概念来解决,collection属性是resultMap高级结果映射的子集,首先,在本例中我们使用的是集合元素来解决多对多的查询 ...
- 《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模
2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到 ...
- django 的多对多关系
django里自带的多对多表创建 其实就是两个多对一关系各自关联,在第三张表上 多对多的增加 add()可以传数值 例如 add(1)或数组 add(*[2,3]) 多对多反向操作 自己创建第三张表, ...
随机推荐
- Qt-获取网络接口信息的综合示例
在前面的文章中介绍了与 获 取 本 机 网 络 信 息 相 关 的 类 常 用 的 有 4 个 , 分 别 是 : QHostAddress, QHostInfo, QNetworkInterface ...
- thymeleaf 基本语法
四.标准表达式语法 · 简单表达式 (simple expressions) ${...} 变量表达式 *{...} 选择变量表达式 #{...} 消息表达式 @{...} 链接url表达式 ...
- mui 重写back 调用back方法,实现返回就即时刷新页面
需求: 从A-----b页面 B操作完后再返回A ,这时A页面数据变化 1.先是针对安卓机可以点击按钮返回,也可以用本机的返回键返回 监听本机的返回按钮,如果点击就调用写好的自定义刷新事件 (fun ...
- iOS之多线程浅谈
1)并发和并行的区别 在软件开发中不可避免的会遇到多线程的问题,在iOS客户端开发(或者.NET的winform或者wpf这样的cs程序)中就更不可避免的会用到多线程,在bs类型的web项目中要考虑一 ...
- 51nod贪心算法入门-----独木舟问题
独木舟问题 n个人,已知每个人体重,独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? 分析:按照 ...
- 压力测试之apache benchmark
ab 的全称是 ApacheBench , 是 Apache 附带的一个小工具 , 专门用于 HTTP Server 的 benchmark testing , 可以同时模拟多个并发请求.前段时间看到 ...
- 【IT历史】SP和CP
1.什么是SP?SP是英文Service Provider的缩写,中文翻译为服务提供商,通常是指在移动网内运营增值业务的社会合作单位.它们建立与移动网络建立相连的服务平台,为手机用户提供一系列信息服务 ...
- 如何在JS中获取Request方法
方法 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = ne ...
- repo manifest xml 文件修改后提交命令
git push origin dev(本地分支):refs/for/tv/Internal_Jb910_develop_t
- NSAssert使用摘抄
#define NSAssert(condition, desc, ...) 只有条件condition满足,才会执行下一个语句,否则输出断言错误. 例如: NSAssert(1 != 2, @&qu ...