NHibernte教程(10)--关联查询
本节内容
- 关联查询引入
- 一对多关联查询
- 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中提供的三种查询方法实现了父子关联查询,并初步探讨了条件查询中比较深入的话题。希望对你有所帮助。下一篇开始讨论NHibernate中的多对多映射关系和查询。
NHibernte教程(10)--关联查询的更多相关文章
- 黑马lavarel教程---10、lavarel模型关联
黑马lavarel教程---10.lavarel模型关联 一.总结 一句话总结: 1.模型关联比较方便,一次定义,后面都可以使用 2.关联关系 使用动态属性进行调用 1.一对多,多对多实例? 一对多: ...
- [转]NHibernate之旅(10):探索父子(一对多)关联查询
本节内容 关联查询引入 一对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 关联查询引入 在NHibernate中提供了三种查询方式给我们选择:NH ...
- NHibernate教程(11)--多对多关联查询
本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...
- mybatis实战教程二:多对一关联查询(一对多)
多对一关联查询 一.数据库关系.article表和user表示多对一的关系 CREATE TABLE `article` ( `id` ) NOT NULL AUTO_INCREMENT, `user ...
- MyBatis入门学习教程-实现关联表查询
一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...
- CRL快速开发框架系列教程十三(嵌套查询)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- [译]Vulkan教程(10)交换链
[译]Vulkan教程(10)交换链 Vulkan does not have the concept of a "default framebuffer", hence it r ...
- [NHibernate]一对多关系(关联查询)
目录 写在前面 文档与系列文章 一对多查询 总结 写在前面 上篇文章介绍了nhibernate的一对多关系如何配置,以及级联删除,级联添加数据的内容.这篇文章我们将学习nhibernate中的一对多关 ...
- [NHibernate]多对多关系(关联查询)
目录 写在前面 文档与系列文章 多对多关系关联查询 总结 写在前面 上篇文章介绍了nhibernate中对一对多关系进行关联查询的几种方式,以及在使用过程需要注意的问题.这篇文章对多对多关系的查询处理 ...
随机推荐
- TCP/IP 主机路由表获取
介绍在IP协议中主机的路由表获取方法: 主机初始化路由表: 直接相连路由:接口初始化时,自动获取直连主机和网络的路由信息 间接相连路由:通过执行route命令,手动初始化路由表 ICMP路由请求和通告 ...
- kickstart自动化安装--tftp+nfs+dhcp
使用kickstart实现Centos 自动化安装 Kickstart自动化安装简介: 规模化:同时装配多台 服务器 自动化 :安装系统,配置各种服务 远程实现:不需要光盘,U盘等安装介质 优势: ( ...
- Fluent Validation with Web Api 2
using FluentValidation;using FluentValidation.Attributes;using System;using System.Collections.Gener ...
- [Scoi2014]方伯伯的玉米田 二维树状数组+动态规划
考试最后半个小时才做这道题.十分钟写了个暴力还写挂了..最后默默输出n.菜鸡一只. 这道题比较好看出来是动规.首先我们要明确一点.因为能拔高长度任意的一段区域,所以如果从i开始拔高,那么一直拔高到n比 ...
- 敏捷视界:Scrum起源、Scrum术语
Scrum起源 Scrum的原始含义 Scrum原始含义是指英式橄榄球次要犯规时在犯规地点对阵争球.争球双方各有8个队员参与,各方出3名前锋队员,并肩各站成一横排,面对面躬身互相顶肩,中间形成一条通道 ...
- css 定位功能position
Static 定位 HTML元素的默认值,即没有定位,元素出现在正常的流中.静态定位的元素不会受到top, bottom, left, right影响. 相对定位Relative相对定位元素的定位是相 ...
- python学习===从一个数中分解出每个数字
题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数",因为153=1 ...
- Linux - 简明Shell编程12 - 定制输出(ColorOutput)
脚本地址 https://github.com/anliven/L-Shell/tree/master/Shell-Basics 示例脚本及注释 #!/bin/bash echo -e "\ ...
- Vue自定义事件
前面的话 父组件使用props传递数据给子组件,子组件怎么跟父组件通信呢?这时,Vue的自定义事件就派上用场了.本文将详细介绍Vue自定义事件 事件绑定 每个 Vue 实例都实现了事件接口 (Even ...
- 老司机和你深聊 Kubenertes 资源分配之 Request 和 Limit 解析
欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云容器服务团队 Kubernetes是一个容器集群管理平台,Kubernetes需要统计整体平台的资源使用情况,合理地将资源分配 ...