本节内容

  • 关联查询引入
  • 一对多关联查询
    • 1.原生SQL关联查询
    • 2.HQL关联查询
    • 3.Criteria API关联查询
  • 结语

关联查询引入

在NHibernate中提供了三种查询方式给我们选择:NHibernate查询语言(HQL,NHibernate Query Language)、条件查询(Criteria API,Query By Example(QBE)是Criteria API的一种特殊情况)、原生SQL(Literal SQL,T-SQL、PL/SQL)。这一节分别使用这三种方式来关联查询。

首先看看上一篇我们为Customer和Order建立的父子关系:

一对多关联查询

1.原生SQL关联查询

在关系模型中:可以使用子表作为内连接查询Customer,像这样:

select * from Customer c inner join Order o on c.CustomerId=o.CustomerId where o.CustomerId=<id of the Customer>

使用父表作为内连接查询Order,像这样:

select * from Oder o inner join Customer c on o.CustomerId=c.CustomerId where o.OrderId=<id of the Order>

下面我们来看看在NHibernate中使用原生SQL查询。这篇来完成查询订单在orderData之后的顾客列表不同查询的写法。

public IList<Customer> UseSQL_GetCustomersWithOrders(DateTime orderDate)
{
return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}"+
" inner join [Order] o on o.Customer={customer}.CustomerId where o.OrderDate> :orderDate")
.AddEntity("customer", typeof(Customer))
.SetDateTime("orderDate", orderDate)
.List<Customer>();
}

具体情况是:实例化IQuery接口;使用ISession.CreateSQLQuery()方法,传递的参数是SQL查询语句;{Customer.*}标记是Customer所有属性的简写。 使用AddEntity查询返回的持久化类,SetDataTime设置参数,根据不同类型,方法名不同。

2.HQL关联查询

查询订单在orderData之后的顾客列表的HQL关联查询写法:

public IList<Customer> UseHQL_GetCustomersWithOrders(DateTime orderDate)
{
return _session.CreateQuery("select distinct c from Customer c inner join c.Orders o where o.OrderDate > :orderDate")
.SetDateTime("orderDate", orderDate)
.List<Customer>();
}

这里使用基于面向对象的HQL,一目了然,符合面向对象编程习惯。

写个测试用例测试UseHQL_GetCustomersWithOrdersTest()查询方法是否正确:

[Test]
public void UseHQL_GetCustomersWithOrdersTest()
{
IList<Customer> customers = _relation.UseHQL_GetCustomersWithOrders(new DateTime(2008, 10, 1));
foreach (Customer c in customers)
{
foreach (Order o in c.Orders)
{
Assert.GreaterOrEqual(o.OrderDate, new DateTime(2008, 10, 1));
}
}
foreach (Customer c in customers)
{
Assert.AreEqual(1, customers.Count<Customer>(x => x == c));
}
}

首先调用UseHQL_GetCustomersWithOrders()方法查询订单在2008年10月1号之后的顾客列表,遍历顾客列表,断言顾客为预期的1个,他的订单时间在2008年10月1号之后。OK!测试成功。注意:这个测试用例可测试本篇所有的关联查询。

3.Criteria API关联查询

我们使用CreateCriteria()在关联之间导航,很容易地在实体之间指定约束。这里第二个CreateCriteria()返回一个ICriteria的新实例,并指向Orders实体的元素。在查询中子对象使用子CreateCriteria语句,这是因为实体之间的关联我们在映射文件中已经定义好了。还有一种方法使用CreateAlias()不会创建ICriteria的新实例。

这个例子返回顾客列表有重复的,不是我们想要的结果。

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
{
return _session.CreateCriteria(typeof(Customer))
.CreateCriteria("Orders")
.Add(Restrictions.Gt("OrderDate", orderDate))
.List<Customer>();
}

预过滤

使用ICriteria接口的SetResultTransformer(IResultTransformer resultTransformer)方法返回满足特定条件的Customer。上面例子中使用条件查询,观察其生成的SQL语句并没有distinct,这时可以使用NHibernate.Transform命名空间中的方法或者使用NHibernate提供的NHibernate.CriteriaUtil.RootEntity、NHibernate.CriteriaUtil.DistinctRootEntity、NHibernate.CriteriaUtil.AliasToEntityMap静态方法实现预过滤的作用。那么上面的查询应该修改为:

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
{
return _session.CreateCriteria(typeof(Customer))
.CreateCriteria("Orders")
.Add(Restrictions.Gt("OrderDate", orderDate))
.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
//或者.SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity)
.List<Customer>();
}

这个例子从转换结果集的角度实现了我们想要的效果。

投影

调用SetProjection()方法可以实现应用投影到一个查询中。NHibernate.Criterion.Projections是Projection的实例工厂,Projections提供了非常多的方法,看看下面的截图,下拉列表中的方法是不是很多啊:

现在可以条件查询提供的投影来完成上面同样的目的:

public IList<Customer> UseCriteriaAPI_GetDistinctCustomers(DateTime orderDate)
{
IList<int> ids = _session.CreateCriteria(typeof(Customer))
.SetProjection(Projections.Distinct(Projections.ProjectionList()
.Add(Projections.Property("CustomerId"))
)
)
.CreateCriteria("Orders")
.Add(Restrictions.Gt("OrderDate", orderDate))
.List<int>(); return _session.CreateCriteria(typeof(Customer))
.Add(Restrictions.In("CustomerId", ids.ToArray<int>()))
.List<Customer>();
}

我们可以添加若干的投影到投影列表中,例如这个例子我添加一个CustomerId属性值到投影列表中,这个列表中的所有属性值都设置了Distinct投影,第一句返回订单时间在orderDate之后所有顾客Distinct的CustomerId,第二句根据返回的CustomerId查询顾客列表。达到上面的目的。这时发现其生成的SQL语句中有distinct。我们使用投影可以很容易的组合我们需要的各种方法。

[转]NHibernate之旅(10):探索父子(一对多)关联查询的更多相关文章

  1. MyBatis:一对多关联查询

    MyBatis从入门到放弃四:一对多关联查询 前言 上篇学习了一对一关联查询,这篇我们学习一对多关联查询.一对多关联查询关键点则依然是配置resultMap,在resultMap中配置collecti ...

  2. MyBatis多对一,一对多,多对多,一对多关联查询

    一.Person实体类 1 public class Person { 2 private Integer personId; 3 private String name; 4 private Int ...

  3. MyBatis初级实战之六:一对多关联查询

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. 7.mybatis一对多关联查询

    和第5节一对一查询类似,但是不同的是,一对一使用的是association,而一对多使用collection. 实例: 1个班级Class,对应1个老师Teacher,对应多个学生Student 1. ...

  5. MyBitis(iBitis)系列随笔之五:多表(一对多关联查询)

    MyBitis(iBitis)系列随笔之一:MyBitis入门实例 MyBitis(iBitis)系列随笔之二:类型别名(typeAliases)与表-对象映射(ORM) MyBitis(iBitis ...

  6. MyBatis从入门到放弃四:一对多关联查询

    前言 上篇学习了一对一关联查询,这篇我们学习一对多关联查询.一对多关联查询关键点则依然是配置resultMap,在resultMap中配置collection属性,别忽略了ofType属性. 搭建开发 ...

  7. MyBatis关联查询,一对多关联查询

    实体关系图,一个国家对应多个城市 一对多关联查询可用三种方式实现: 单步查询,利用collection标签为级联属性赋值: 分步查询: 利用association标签进行分步查询: 利用collect ...

  8. mybatis一对多关联查询+pagehelper->分页错误

    mybatis一对多关联查询+pagehelper->分页错误. 现象: 网上其他人遇到的类似问题:https://segmentfault.com/q/1010000009692585 解决: ...

  9. mybatis collection 一对多关联查询,单边分页的问题总结!

    若想直接通过sql实现多级关联查询表结构得有2 个必不可少的字段:id ,parentId,levelId id:主键id, parentId:父id levelId:表示第几级(表本身关联查询的时候 ...

随机推荐

  1. iOS 高级开发 runtime(三)

    三 .动态添加方法 我们可以通过runtime动态地添加方法.那么到底啥叫动态添加方法呢?动态添加方法就是当我们程序运行时才知道我们应该调用哪个方法.我们首先需要了解这一点,当我们编写完一段代码后,我 ...

  2. 01_根据Id查询User的数据

    [工程目录] [数据库表中内容 user表] [sqlMapConfig.xml配置文件主要内容] 简述:sqlMapConfig.xml配置文件主要有两个作用: 1.配置和数据连接的相关信息,例如事 ...

  3. Linux下的另一个词典GoldenDict

    以前一直在用statdict,突然发现了一个好用的东西Goldendict. 转载丁香园上一篇文章:http://www.dxy.cn/bbs/topic/20455142 Goldendict 话说 ...

  4. leetcode problem 6 ZigZag Conversion

    The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like ...

  5. js 中如何通过提示框跳转页面

    通过提示框跳转页面 <!doctype html> <html lang="en"> <head> <meta charset=" ...

  6. 使用South时候由于两个相同id的文件引起的问题

    由于之前版本控制的一个小失误, 在主分子上面调用python manage.py makemigrations生成了 0058_auto__add_unique_setting_name_value. ...

  7. dustjs

    http://akdubya.github.io/dustjs/ https://github.com/linkedin/dustjs

  8. 配置Apache服务器 数据库mySQL

    Mac 配置  apache   php 详细解说 一.开启apache 并切改变引导 1.打开终端  输入:sudo apachectl start    回车,关闭终端 2.打开浏览器,地址栏输入 ...

  9. app应用程序本地化--备用

    一.简介 * 使用本地化功能,可以轻松地将应用程序翻译成多种语言,甚至可以翻译成同一语言的多种方言 * 如果要添加本地化功能,需要为每种支持的语言创建一个子目录,称为”本地化文件夹”,通常使用.lpr ...

  10. 移动web HTML5使用photoswipe模仿微信朋友圈图片放大浏览

    先来几张效果图: 点击其中一张照片可放大,可支持图片文字描述: 同时支持分享功能: 支持手势放大缩小 使用js框架是PhotoSwipe. PhotoSwipe是一个图片放大插件,兼容pc和移动端,经 ...