NHibernate之旅(10):探索父子(一对多)关联查询
来源:互联网 发布:linux集成开发环境 编辑:程序博客网 时间:2024/05/21 06:52
本节内容
- 关联查询引入
- 一对多关联查询
- 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中的多对多映射关系和查询。
本系列链接:NHibernate之旅系列文章导航
下次继续分享NHibernate!
- NHibernate之旅(10):探索父子(一对多)关联查询
- NHibernate之旅(10):探索父子(一对多)关联查询
- NHibernate之旅(9):探索父子关系(一对多关系)
- NHibernate之旅(9):探索父子关系(一对多关系)
- NHibernate之旅(9):探索父子关系(一对多关系)
- [NHibernate]一对多关系(关联查询)
- [NHibernate]一对多关系(关联查询)
- NHibernate之旅(11):探索多对多关系及其关联查询
- NHibernate之旅(11):探索多对多关系及其关联查询
- NHibernate之旅(11):探索多对多关系及其关联查询
- NHibernate之旅(11):探索多对多关系及其关联查询
- 一对多关联查询
- NHibernate之旅(3):探索查询之NHibernate查询语言(HQL)
- NHibernate之旅(3):探索查询之NHibernate查询语言(HQL)
- NHibernate之旅(3):探索查询之NHibernate查询语言(HQL)
- NHibernate之旅(3):探索查询之NHibernate查询语言(HQL)
- mybaits 一对多 关联查询
- Mybatis一对多关联查询
- (一) Linux Centos7下SVN服务器搭建详细教程
- java的内存模型
- loadrunner动态从mysql取值 [需要下载跟数据库服务器一致的dll,32位或64位]
- 线程基础:线程(2)——JAVA中的基本线程操作(上)
- [学习笔记]设计模式[2]-{装饰者模式}
- NHibernate之旅(10):探索父子(一对多)关联查询
- Apache OpenNLP下载
- 比好看的一些自定义SeekBar
- 什么是Docker
- Windows 10四大版本官方对比:国人肯定专业版
- 获取系统/sdcard存储空间路径无效的处理
- 同步/异步 与 阻塞/非阻塞的区别
- 线程基础:线程(3)——JAVA中的基本线程操作(中)
- [学习笔记]设计模式[4]-{单件模式}