目录

写在前面

文档与系列文章

多对多关系关联查询

总结

写在前面

上篇文章介绍了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]一对多关系(级联删除,级联添加)

[NHibernate]一对多关系(关联查询)

多对多关系关联查询

多对多关系非常常见,比如系统中常用的权限管理问题,一个用户有多个权限,当然一个权限可以属于多个用户(这样描述只是为了对多对多关系有个感性的认识)。那么在咱们的客户/订单/产品,这三张表中有没有多对多的关系呢?

订单可以有多个产品,一种产品可以属于多个订单(这个地方有点绕,如果再有一个数量的字段,比较好理解,下一个订单,只是库存减少了,但id还是那个id)。关系图如下:

其中表TB_OrderProduct为order和product的关系表,字段OrderID和ProductID为联合主键。

添加联合主键的sql语句如下:

 ALTER TABLE tb_orderproduct WITH NOCHECK ADD
CONSTRAINT [PK_orderproduct] PRIMARY KEY NONCLUSTERED
(
orderid,
productid
)

首先修改Order类

     /// <summary>
/// 描述:订单实体,数据库持久化类
/// 创建人:wolfy
/// 创建时间:2014-10-16
/// </summary>
public class Order
{
/// <summary>
/// 订单id
/// </summary>
public virtual Guid OrderID { set; get; }
/// <summary>
/// 下订单时间
/// </summary>
public virtual DateTime OrderDate { set; get; }
/// <summary>
/// 下订单的客户,多对一的关系:orders对应一个客户
/// </summary>
public virtual Customer Customer { set; get; }
/// <summary>
/// 多对多关系,一个订单下可以有多个产品
/// </summary>
public virtual IList<Product> Products { set; get; }
}

修改Order.hbm.xml映射文件如下

 <?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain" namespace="Wolfy.Shop.Domain.Entities">
<class name="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain" table="TB_Order">
<id name="OrderID" column="OrderID" type="Guid" unsaved-value="null">
<generator class="assigned" />
</id>
<property name="OrderDate" column="OrderDate" type="DateTime"
not-null="true" />
<!--多对一关系:Orders属于一个Customer-->
<many-to-one name="Customer" column="CustomerID" not-null="true"
class="Wolfy.Shop.Domain.Entities.Customer,Wolfy.Shop.Domain"
foreign-key="FK_TB_Order_TB_Customer" />
<!--多对多关系:order下有多个product-->
<bag name="Products" generic="true" table="TB_OrderProduct">
<key column="OrderID" foreign-key="FK_TB_OrderProduct_TB_Order"/>
<many-to-many column="ProductID" class="Wolfy.Shop.Domain.Entities.Product,Wolfy.Shop.Domain"
foreign-key="FK_TB_OrderProduct_TB_Product"/> </bag>
</class>
</hibernate-mapping>

修改Product类

     /// <summary>
/// 描述:商品实体,数据库持久化类
/// 创建人:wolfy
/// 创建时间:2014-10-16
/// </summary>
public class Product
{
/// <summary>
/// 商品id
/// </summary>
public virtual Guid ProductID { set; get; }
/// <summary>
/// 商品名称
/// </summary>
public virtual string Name { set; get; }
/// <summary>
/// 商品单价
/// </summary>
public virtual decimal Price { set; get; }
/// <summary>
/// 多对多关系:Product属于多个Orders
/// </summary>
public virtual IList<Order> Orders { get; set; } }

Mappings文件夹中新建Product.hbm.xml映射文件

 <?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain" namespace="Wolfy.Shop.Domain.Entities">
<class name="Wolfy.Shop.Domain.Entities.Product,Wolfy.Shop.Domain" table="TB_Product">
<id name="ProductID" column="ProductID" type="Guid" unsaved-value="null">
<generator class="assigned" />
</id>
<property name="Name" column="Name" type="String"
not-null="true" />
<property name="Price" column="Price" type="float"
not-null="true" />
<!--多对多关系:product属于多个orders-->
<bag name="Orders" generic="true" table="TB_OrderProduct">
<key column="ProductID" foreign-key="FK_TB_OrderProduct_TB_Product"/>
<many-to-many column="OrderID" class="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain"
foreign-key="FK_TB_OrderProduct_TB_Order"/>
</bag>
</class>
</hibernate-mapping>

修改映射文件的属性,这个动作应该养成一个习惯,不管你写的配置文件对不对,只要添加了映射文件,就修改它的属性,如图:

通过上面对比,你会发现多对多关系many-to-many节点的配置相似,只是方向有点区别。

原生SQL查询

查询客户的所有的订单和订单下所有的产品。

CustomerData.cs

         /// <summary>
/// 通过sql查询客户下的订单和产品信息
/// </summary>
/// <param name="cutomerID"></param>
/// <returns></returns>
public IList<Customer> GetCustomerOrderProductsBySQL(Guid cutomerID)
{
//获得ISession实例
ISession session = NHibernateHelper.GetSession();
//使用inner join关联多个表进行查询
return session.CreateSQLQuery("select distinct c.* from TB_Customer c" +
" inner join TB_Order o on o.CustomerID=c.CustomerID" +
" inner join TB_OrderProduct op on o.OrderID=op.OrderID" +
" inner join TB_Product p on op.ProductID=p.ProductID where c.CustomerID=:CustomerID")
//使用AddEntity设置返回的实体。
.AddEntity("Customer", typeof(Customer))
.SetGuid("CustomerID", cutomerID)
.List<Customer>();
}

生成的sql语句

HQL查询

查询客户的所有的订单和订单下所有的产品。

CustomerData.cs

         /// <summary>
/// 通过HQL查询客户下的订单和产品信息
/// </summary>
/// <param name="cutomerID"></param>
/// <returns></returns>
public IList<Customer> GetCustomerOrderProductsByHQL(Guid cutomerID)
{
//获得ISession实例
ISession session = NHibernateHelper.GetSession();
//使用HQL基于面向对象的查询方式
return session.CreateQuery("select distinct c from Customer c inner join c.Orders o inner join o.Products where c.CustomerID=:CustomerID")
.SetGuid("CustomerID", cutomerID)
.List<Customer>();
}

生成的sql语句

通过查看sql及HQL语句可以知道,c.Orders o inner join o.Products 内部为我们查询了所有Order下的所有产品,你会发现我们的查询中并没有出现表TB_OrderProduct,而在sql语句中出现了该表,因为这些信息在映射文件已经描述了。nhibernate通过映射文件,知道如何关联,该关联那张数据表。

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>();
}

上面这段代码是@李永京文章中的,这种方式也尝试了c.Orders.elements,总是报以下异常:

NHibernate.Hql.Ast.ANTLR.QuerySyntaxException : c.Orders.elements is not mapped [select distinct c from Customer c , c.Orders.elements o where o.OrderDate > :orderDate]

也许,大概elements在nhibernate 4.0版本中废除了吧,最后没办法,就通过我上面写的那种方式实现了HQL查询,毕竟条条大路通罗马,不能在一条路上吊死吧。

Criteria API关联查询

通过HQL方式,我们已经知道了实体间的关系已经在映射文件中定义好了,所以我们在查询子对象使用子CreateCriteria语句关联对象之间导航,可以很容易地在实体之间指定约束。这里第二个CreateCriteria()返回ICriteria的新实例,并指向Orders实体的元素。第三个指向Products实体的元素。

查询客户的所有的订单和订单下所有的产品。

CustomerData.cs

         /// <summary>
/// 通过HQL查询客户下的订单和产品信息
/// </summary>
/// <param name="cutomerID"></param>
/// <returns></returns>
public IList<Customer> GetCustomerOrderProductsByCriteriaAPI(Guid cutomerID)
{
//获得ISession实例
ISession session = NHibernateHelper.GetSession();
return session.CreateCriteria(typeof(Customer))
.Add(Restrictions.Eq("CustomerID", cutomerID))
.CreateCriteria("Orders")
.CreateCriteria("Products")
.List<Customer>();
}

生成的sql语句

此时查询出来的数据有两条,因为有两个产品,没有对其进行去重。

测试数据如下:

TB_Customer表

TB_Order表

TB_OrderProduct表

TB_Product表

总结

在学习多对多关联查询时,在c.Orders.elements的地方卡在那个地方了,这块还需要在查一查nhibernate版本之间是不是有差异。被一个问题,折腾到现在,本来打算十点半睡觉的(每天最晚十点半上床睡觉),我基本是不熬夜的,有点强迫症,不想带着问题睡觉,很晚了,就写到这儿吧。

参考地址:http://www.cnblogs.com/lyj/archive/2008/10/27/1320764.html#!comments

[NHibernate]多对多关系(关联查询)的更多相关文章

  1. Hibernate,关系映射的多对一单向关联、多对一双向关联、一对一主键关联、一对一外键关联、多对多关系关联

    2018-11-10  22:27:02开始写 下图内容ORM.Hibernate介绍.hibername.cfg.xml结构: 下图内容hibernate映射文件结构介绍 下图内容hibernate ...

  2. Mysql多对多关系的查询

    1.创建user表 2.创建gateway表 3.创建user_gateway表 4.创建device表 5.创建gateway_device表 6.创建一个实体类 public class Devi ...

  3. MyBatis-Plus不写任何resultMap和SQL执行一对一、一对多、多对多关联查询

    对于一对一,一对多的关联查询,Mybatis-Plus官方示例(mybatis-plus-sample-resultmap)在处理时,需要编写查询方法及配置resultMap,并且写SQL. 为了简化 ...

  4. [转]NHibernate之旅(11):探索多对多关系及其关联查询

    本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...

  5. NHibernate教程(11)--多对多关联查询

    本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...

  6. [NHibernate]一对多关系(关联查询)

    目录 写在前面 文档与系列文章 一对多查询 总结 写在前面 上篇文章介绍了nhibernate的一对多关系如何配置,以及级联删除,级联添加数据的内容.这篇文章我们将学习nhibernate中的一对多关 ...

  7. NHibernate多对多关联映射的实现

    上次用EF演示了数据库多对多关系的操作,这次我们还是引用上次的案例,来演示如何在C#当中使用NHibernate. 首先介绍一下NHibernate框架的来源.熟悉Java编程的读者肯定知道Hiber ...

  8. 用NHibernate处理带属性的多对多关系

    1.引言 老谭在面试开发者的时候,为了考察他们的数据库开发能力,经常祭出我的法宝,就是大学数据库教程中讲到的一个模式:学生选课.这个模式是这种: 在这个模式中,学生(Student)和课程(Cours ...

  9. NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

    摘要 NHibernate的多对多关系映射由many-to-many定义. 从这里下载本文的代码NHibernate Demo 1.修改数据库 添加Product表 添加ProductOrder表 数 ...

随机推荐

  1. sublime text3的一些插件安装方法和使用

    sublime text部分插件使用方法在线安装package Control的方法:    ctrl+~ 输入如下代码:        import urllib2,os; pf='Package ...

  2. shell统计指定范围内的所有质数以及它们的和

    #!bin/bash a= $) ;do n= $x);do ];then n=$[$n+] fi done ];then { echo -n -e "$x\t" sum=$[$s ...

  3. 3D坦克大战游戏iOS源码

    3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...

  4. Java基础知识笔记(七:接口、变量作用域和参数传递)

    一.接口 Java语言不允许一个子类拥有多个直接父类,即任何子类只能有一个直接父类.但允许一个类实现多个接口,即在定义类的接口名称列表中可以包含1个或多个接口名称,从而实现多重继承的特性.接口的定义格 ...

  5. mybatis 快速入门

    1 . 定义  java实体类 User,建立user表 读者请自行完成准备工作.  User 类 有 id, name,age 属性  user  表 中 id,name,age字段  id自增长  ...

  6. http status 状态码汇总

    常见HTTP状态码 200 OK 301 Moved Permanently 302 Found 304 Not Modified 307 Temporary Redirect 400 Bad Req ...

  7. HDU3555 Bomb[数位DP]

    Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submi ...

  8. C#基础系列——一场风花雪月的邂逅:接口和抽象类

    前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗 ...

  9. Codeforces Round #381(div 2)

    A.(分类讨论) 题意:你有n本书,有三种买书方案,花a元买1本,花b元买2本,花c元买3本,问最少花多少钱,使得你书的总数是4的倍数 分析:分类讨论的题,但是要注意你可以买超过4本书--可以买5本. ...

  10. C语言拾遗(一)

    越来越体会到C语言的重要性,不管是在计算机底层的理解上,还是在算法数据结构上,所以遂决定重新拾起C语言,不定期更新一些知识点. 推荐博客:http://blog.csdn.net/itcastcpp ...