恋恋风尘

Coding is just my hobby……

博客园 首页 新随笔 联系 订阅 管理
  8 随笔 :: 0 文章 :: 79 评论 :: 49935 阅读

#

摘要: 方法与思想高于平台与语言。平台与语言仅是工具,开发方法与思想才是精髓。掌握了开发方法与思想,学习与使用一个新平台、一门新语言有啥难度,几天时间就上手,边做项目边熟悉。 开发人员的水平高低、薪水多少,主要是由掌握的方法、思想、经验决定,而不是由平台与语言决定。 阅读全文
posted @ 2016-01-02 00:53 恋恋风尘 阅读(271) 评论(0) 推荐(3) 编辑

2011年5月16日 #

一、引言

       NHibernate3.0增加了一种新的查询API——QueryOver。QueryOver构建在NHibernate原有的 ICriteria API之上,支持Lambda表达式与扩展方法,可编写类型安全的查询语句,这样就克服了ICriteria API字符串硬编码的弊端。在上一篇文章中《NHibernate 3.x新功能实践(一) QueryOver(上)》通过一个简单的实例,介绍了QueryOver进行条件筛选(Restriction)、连接(Join)等应用,在这篇文章中将介绍投影(Projection)、把投影结果转成DTO、分页、子查询(Subquery)等常见应用场景。 在文章《NHibernate 3.x新功能实践(一) QueryOver(上)》最后提供实例源代码下载。

二、开发环境与工具

三、实例场景

      参见《NHibernate 3.x新功能实践(一) QueryOver(上)

四、查询场景

1. 投影且把投影结果转成DTO (Projection)

 订单DTO类:OrderDTO

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace MyWorkShop.Model.DTOs
 7 {
 8     public class OrderDTO
 9     {
10         public Guid Id { getset; }
11         public string CustomerName getset; }
12         public DateTime OrderedDateTime { getset; }
13         public Decimal? Amount { getset; } 
14     }
15 }

 (1)根据订单号查找订单,并用LINQ TO Object转成OrderDTO

 1 public OrderDTO GetOrderDTOById(Guid id)
 2 {
 3     OrderDTO dto = null;
 4 
 5     Customer customer = null;
 6 
 7     using (var session = NHibernateSession)
 8     using (var transaction = session.BeginTransaction())
 9     {
10         dto = session.QueryOver<Order>()
11             .JoinAlias(o => o.Customer, () => customer)
12             .Where(o => o.Id == id)
13             .Select(o => o.Id, o => customer.Name, o => o.OrderedDateTime,o => o.Amount)
14             .List<object[]>()
15             .Select(props => new OrderDTO
16             {
17                 Id = (Guid)props[0],
18                 CustomerName=(string)props[1],
19                 OrderedDateTime = (DateTime)props[2],
20                 Amount = (decimal)props[3]
21             }).SingleOrDefault();
22 
23         transaction.Commit();
24     }
25 
26     return dto;
27 }

  输出的SQL: 

SELECT this_.Id as y0_, customer1_.Name as y1_, this_.OrderedDateTime as y2_, this_.Amount as y3_ FROM MyWorkShop_Order this_ inner join MyWorkShop_Customer customer1_ on this_.CustomerId=customer1_.Id WHERE this_.Id = @p0;@p0 = b0a7f211-0404-4df5-93be-9ee501216c5c

 代码说明:

  •  代码中的第一个Select进行投影(Projection)操作,取出所要的4个字段,分别为o.Idcustomer.Nameo.OrderedDateTime、o.Amount;
  • .List<object[]>()把投影得到的4个字段放到一个object[]数组中;
  • 代码中的第二个Select使用LINQ TO Object(此时与NHibernate无关),新建一个OrderDTO对象,并把object[]数组的4个字段依次赋给OrderDTO对象,字段赋值之前需进行强制类型转换,把object类型转成相应的类型;
  • 由于需对每个字段进行强制类型转换,所以代码不太干净且容易出错,而且当字段类型变化时需手工修改代码,不利于代码重构,所以不推荐使用此方案,较好的方案是下面介绍的使用NHibernate内置方法把投影结果转成DTO。
 (2)根据订单号查找订单,并用NHibernate内置方法转成OrderDTO
 1 public OrderDTO GetOrderDTOById(Guid id)
 2 {
 3     OrderDTO dto = null;
 4 
 5     //定义用于内连接的别名变量,该变量必须赋值为null
 6     Customer customer = null;
 7 
 8     using (var session = NHibernateSession)
 9     using (var transaction = session.BeginTransaction())
10     {
11         dto = session.QueryOver<Order>()
12             //创建用于内连接的别名customer
13             .JoinAlias(o => o.Customer, () => customer)
14             .Where(o => o.Id == id)
15             .SelectList(list =>list
16                 .Select(o => o.Id).WithAlias(() => dto.Id)    //给投影列取别名,用于把投影结果转成DTO
17                 .Select(o => customer.Name).WithAlias(() => dto.CustomerName)
18                 .Select(o => o.OrderedDateTime).WithAlias(() => dto.OrderedDateTime)
19                 .Select(o => o.Amount).WithAlias(() => dto.Amount)
20             )
21             //把投影结果转成DTO
22             .TransformUsing(Transformers.AliasToBean<OrderDTO>())
23             .SingleOrDefault<OrderDTO>();
24 
25         transaction.Commit();
26     }
27 
28     return dto;
29 }
输出的SQL:

       同上,略

代码说明:
  • SelectList()包含要投影的列;
  • WithAlias()给每个投影得到的列取别名,用于投影结果转DTO;
  •  .TransformUsing(Transformers.AliasToBean<OrderDTO>())把投影结果转DTO。

2. 分组统计(Group)

(1)统计每个客户所有订单的总金额,以及客户Id
 1 public IEnumerable<CustomerIdAndTotalAmountDTO> GetCustomerIdAndTotalAmountDTOs()
 2 {
 3     CustomerIdAndTotalAmountDTO dto = null;
 4 
 5     IEnumerable<CustomerIdAndTotalAmountDTO> retList = null;
 6 
 7     using (var session = NHibernateSession)
 8     using (var transaction = session.BeginTransaction())
 9     {
10         retList = session.QueryOver<Order>()
11             .SelectList(list => list
12                 .SelectGroup(o => o.Customer.Id).WithAlias(() => dto.CustomerId)
13                 .SelectSum(o => o.Amount).WithAlias(() => dto.TotalAmount)
14             )
15             .TransformUsing(Transformers.AliasToBean<CustomerIdAndTotalAmountDTO>())
16             .List<CustomerIdAndTotalAmountDTO>();
17 
18         transaction.Commit();
19     }
20 
21     return retList;
22 }

  输出的SQL:

NHibernate: SELECT this_.CustomerId as y0_, sum(this_.Amount) as y1_ FROM MyWorkShop_Order this_ GROUP BY this_.CustomerId

  代码说明:

  • .SelectGroup(o => o.Customer.Id)指定分组的列;
  • .SelectSum(o => o.Amount)指定对Amount调用求和聚集函数,除了SelectSum外还有SelectAvg求平均、SelectCount计数、SelectMax求最大、SelectMin求最小等常见的聚集函数。

3. 分页(Paging)

 (1)分页查找

 1 public IEnumerable<OrderDTO> GetOrderDTOsByPage(int pageIndex, int pageSize)
 2 {
 3     OrderDTO dto = null;
 4     Customer customer = null;
 5 
 6     IEnumerable<OrderDTO> retList = null;
 7 
 8     using (var session = NHibernateSession)
 9     using (var transaction = session.BeginTransaction())
10     {
11 
12         retList = session.QueryOver<Order>()
13             .JoinAlias(o => o.Customer, () => customer)
14             .SelectList(list => list
15                 .Select(o => o.Id).WithAlias(() => dto.Id)
16                 .Select(o => customer.Name).WithAlias(() => dto.CustomerName)
17                 .Select(o => o.OrderedDateTime).WithAlias(() => dto.OrderedDateTime)
18                 .Select(o => o.Amount).WithAlias(() => dto.Amount)
19             )
20             .TransformUsing(Transformers.AliasToBean<OrderDTO>())
21             .OrderBy(o=>o.Amount).Desc
22             .Skip(pageIndex * pageSize).Take(pageSize)
23             .List<OrderDTO>();
24 
25         transaction.Commit();
26     }
27 
28     return retList;
29 }

 输出的SQL:

SELECT TOP (@p0) y0_, y1_, y2_, y3_ FROM (SELECT this_.Id as y0_, customer1_.Name as y1_, this_.OrderedDateTime as y2_, this_.Amount as y3_, ROW_NUMBER() OVER(ORDER BY this_.Amount DESCas __hibernate_sort_row FROM MyWorkShop_Order this_ inner join MyWorkShop_Customer customer1_ on this_.CustomerId=customer1_.Id) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;@p0 = 2 [Type: Int32 (0)]@p1 = 2 [Type: Int32 (0)]

 代码说明:

  •  调用Skip()、Take()实现数据分页读取。
(2)计算数据总量
 1 public int GetOrderCount()
 2 {
 3     using (var session = NHibernateSession)
 4     using (var transaction = session.BeginTransaction())
 5     {
 6         int count = session.QueryOver<Order>()
 7             .RowCount();
 8 
 9         transaction.Commit();
10 
11         return count;
12     }
13 }

 输出的SQL:

SELECT count(*as y0_ FROM MyWorkShop_Order this_

 代码说明:

  •  调用RowCount()计算数据总量。

 4. 子查询(Subquery)

 (1)查找金额最大的订单

 1 public Order GetMaxAmountOrder()
 2 {
 3     Order order = null;
 4 
 5     using (var session = NHibernateSession)
 6     using (var transaction = session.BeginTransaction())
 7     {
 8         var maxAmount = NHibernate.Criterion.QueryOver.Of<Order>()
 9             .SelectList(a=>a.SelectMax(o=>o.Amount));
10                 
11         order = session.QueryOver<Order>()
12             .WithSubquery.WhereProperty(o => o.Amount).Eq(maxAmount)
13             .SingleOrDefault();
14 
15         transaction.Commit();
16     }
17     return order;
18 }

输出的SQL:

SELECT this_.Id as Id9_0_, this_.CustomerId as CustomerId9_0_, this_.OrderedDateTime as OrderedD3_9_0_, this_.Amount as Amount9_0_ FROM MyWorkShop_Order this_ WHERE this_.Amount = (SELECT max(this_0_.Amount) as y0_ FROM MyWorkShop_Order this_0_)

 代码说明:

  •  .WithSubquery指定子查询。

五、总结

      本文与上一篇文章通过一个简单的实例,介绍了QueryOver进行条件筛选(Restriction)、连接(Join)、投影(Projection)、把投影结果转成DTO、分页、子查询(Subquery)等常见场景应用。

六、参考资料

       见《NHibernate 3.x新功能实践(一) QueryOver(上)》文章最后。

七、实例源代码下载

       见《NHibernate 3.x新功能实践(一) QueryOver(上)》文章最后。

posted @ 2011-05-16 19:24 恋恋风尘 阅读(4357) 评论(6) 推荐(2) 编辑

2011年5月11日 #

摘要: NHibernate3.0增加了一种新的查询API——QueryOver。QueryOver构建在NHibernate原有的ICriteria API之上,支持Lambda表达式与扩展方法,可编写类型安全的查询语句,这样就克服了ICriteria API字符串硬编码的弊端,可借助VS提供的智能提示方便代码输入,减少输入错误。同时可利用VS等重构功能自动更新因实体字段名更改而导致的查询语句的变更,方便代码重构。本文主要介绍QueryOver的常见应用,并结合一个可运行的实例对各查询场景进行详尽的阐述。 阅读全文
posted @ 2011-05-11 19:46 恋恋风尘 阅读(7124) 评论(4) 推荐(5) 编辑

2009年9月13日 #

摘要: 在NHibernate中如何对没有建立关联关系的实体进行连接操作呢?答案是使用theta-style join。本文首先介绍theta-style join与常见join的区别,然后通过实例具体阐述在NHibernate中对无关联实体进行theta-style join的实现。 阅读全文
posted @ 2009-09-13 21:41 恋恋风尘 阅读(6737) 评论(7) 推荐(1) 编辑

2009年9月5日 #

摘要: 微软牛人Scott Hanselman发布了2009年的.NET与Windows终极开发工具:Scott Hanselman's 2009 Ultimate Developer and Power Users Tool List for Windows,绝对有你想要的东东,绝对不能错过! 阅读全文
posted @ 2009-09-05 18:47 恋恋风尘 阅读(437) 评论(0) 推荐(0) 编辑

2009年9月3日 #

摘要: 今天这篇文章,主要介绍上面(3)中提到的:HQL与Criteria对mapping文件中设置的抓取策略的差异现象,即mapping文件中的fetch="join"抓取策略设置,对Get、Criteria有影响对HQL不影响的现象。当一开始遇到这个现象时,相信园子里的不少朋友会和我一样,还以为是自己的代码写错了或是mapping文件设置错了呢,经过调试确认代码和设置都没错之后,甚感惊讶,就怀疑是NHibernate的Bug。在网上搜索相关资料后才知道Hibernate(NHibernate)存在此现象,My God,我又没有先知先觉,谁想得到呢?气得真想把电脑给砸了,算是被NHibernate耍了几个小时的调试时间,从此以后在实际项目中就再也没在 mapping文件中设置过任何fetching strategy。 阅读全文
posted @ 2009-09-03 14:41 恋恋风尘 阅读(5854) 评论(11) 推荐(1) 编辑

2009年9月1日 #

摘要: 最近在使用NHibernate做系统,而且园子里玩NHibernate的人好像也多了几个,发现Jeffrey Zhao都NHibernate了,所以我也来凑个热闹,写一点自己的实践体会,以与园子里的NHibernate园友进行相互交流和学习。 李永京的NHibernate之旅系列文章导航通俗易懂,相信园子里大部分搞NHibernate的人多多少少都看过,NHibernate组里也有不少关于NHibernate讨论,这次就从NHibernate组里的几个话题展开说一下我的实践体会。 阅读全文
posted @ 2009-09-01 01:00 恋恋风尘 阅读(10500) 评论(36) 推荐(3) 编辑

点击右上角即可分享
微信分享提示