本节内容

  • 关联查询引入
  • 一对多关联查询
    • 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 Q&A

  • 欢迎加入NHibernate中文社区,一起讨论NHibernate知识!
  • 请到NHibernate中文社区下载本系列相关源码。

下次继续分享NHibernate!

转载于:https://www.cnblogs.com/lyj/archive/2008/10/26/1319889.html

NHibernate之旅(10):探索父子(一对多)关联查询相关推荐

  1. mybatis一对多关联查询两种方式

    mybatis一对多关联查询两种方式 前提: 方式一: 方式二: 前提: 现在有两张表,学生表跟教师表,一个教师对应多个学生 教师表: CREATE TABLE `teacher` (`id` int ...

  2. mysql的分页怎么不对_mysql一对多关联查询分页错误问题的解决方法

    xml问价中查询数据中包含list,需要使用collection .... .... 这样的查询系统封装的通用分页查询是不对的,所以需要自己sql中加入分页解决 SELECT you.nick_nam ...

  3. mybatis一对多关联查询_Mybatis 一对一、一对多的关联查询 ?

    <mapper namespace="com.lcb.mapping.userMapper"> <!--association 一对一关联查询 --> &l ...

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

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

  5. mysql一对多关联查询分页_mysql一对多关联查询分页错误问题的解决方法

    xml问价中查询数据中包含list,需要使用collection .... .... 这样的查询系统封装的通用分页查询是不对的,所以需要自己sql中加入分页解决 SELECT you.nick_nam ...

  6. Mybatis多表关联查询(一对多关联查询)

    1.Mybatis一级缓存与二级缓存 目的:提高查询效率,降低数据库查询压力,提升系统整体性能. 一级缓存:默认开启,Session级别,同一个会话内生效. 命中缓存的情况:statementid.S ...

  7. 使用 Mybatis-Plus 进行一对多关联查询

    如果公司允许使用 Mybatis-Plus 进行一对多关联查询,可以在 Service 层中使用 Mybatis-Plus 提供的 Wrapper 来实现.以下是一个使用 Mybatis-Plus W ...

  8. Mybatis一对多关联查询,返回值Map,字段自动映射

    功能描述 由于查询字段和表名都要支持动态配置,故查询返回值需要为List<Map<String,Object>>,不定义值对象. 查询结果列需要支持自动映射,不配置类属性和数据 ...

  9. MyBatis框架学习 DAY_03:如何解决无法封装问题 / 一对一关联查询 / 一对多关联查询

    1. 通过查询时自定义别名的方式解决名称不一致而导致的无法封装数据的问题 假设,向用户组数据表(t_group)表中插入一些测试数据: INSERT INTO t_group (name) VALUE ...

最新文章

  1. full paper(long paper),short paper,oral,poster,workshop,findings
  2. 科创板首发过会,格灵深瞳“三变”交出IPO答卷
  3. Android开发之详解五大布局
  4. NumPy-快速处理数据--ndarray对象--多维数组的存取、结构体数组存取、内存对齐、Numpy内存结构...
  5. 【MySQL】基于MySQL的SQL核心语法实战演练(二)
  6. Kinect开发学习笔记之(七)骨骼数据的提取
  7. kafka源码编译及开发环境搭建
  8. 【Elasticsearch】如何在 Elasticsearch 中轻松编写脚本
  9. 生活杂谈-空调的修理
  10. 体系结构方案 - 临时性数据计算
  11. Object-C 语法基础
  12. js制作网页动态背景
  13. java短信接口_java调用短信接口代码
  14. 【全文翻译】YOLOv1:统一的实时目标检测
  15. 若依的${params.dataScope}
  16. iOS —label自动换行
  17. 最近听到一首挺好听的歌,但是……
  18. 未能创建类型“Genersoft.ZJGL_XD.XDXTXY.XDGLPUBSrv”。
  19. 记录一次详细在线加密PDF解密过程
  20. oracle同义词表信息查询

热门文章

  1. BZOJ 4555 [Tjoi2016Heoi2016]求和
  2. 查看mysql当前表使用的存储引擎(转)
  3. Centos5.6入门学习003之Cenots环境初始化
  4. NETMF Versions 4.1 Release 发布
  5. 直播系统搭建关键步骤与要点!
  6. 网站后端_Flask-第三方库.利用Flask-Socketio扩展构建实时流应用?
  7. Codeforces Round #375 (Div. 2)
  8. 了解mysql的三种不同安装方式的区别
  9. 【WC2016】论战捆竹竿
  10. 后盾网lavarel视频项目---3、lavarel中子控制器继承父控制器以判断是否登录