zoukankan      html  css  js  c++  java
  • NHibernate 3.x新功能实践(二) QueryOver(下)

    一、引言

           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(上)》文章最后。

  • 相关阅读:
    整数的可除性
    椭圆曲线的基本概念
    数组方法分析-笔记
    JS-作用域
    JS-变量存储
    Web框架-inoic
    圣杯布局
    js,php中的面向对象
    正则
    math对象
  • 原文地址:https://www.cnblogs.com/wangyhua/p/4050537.html
Copyright © 2011-2022 走看看