迷恋弦哥

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Using QueryOver projections and aggregates

使用QueryOver投影和聚合

  在一些情况下,只需要某个实体的特定属性.而其他情况下,却可能需要一个聚合函数的结果,比如average或count.本节介绍QueryOver查询中的投影和聚合.

步骤

1.   完成本章简介中的通用步骤.
2.   在Queries类中,添加下面的方法:

View Code
public IEnumerable<NameAndPrice> GetMoviePriceList()
{
  return _session.QueryOver<Movie>()
    .Select(m => m.Name, m => m.UnitPrice)
    .List<object[]>()
    .Select(props =>
      new NameAndPrice()
      {
        Name = (string)props[0],
        Price = (decimal)props[1]
      });
}

3.   在Queries类中,添加下面的方法,该方法获取movies的价格平均值:

View Code
public decimal GetAverageMoviePrice()
{
  var result = _session.QueryOver<Movie>()
    .Select(Projections.Avg<Movie>(m => m.UnitPrice))
    .SingleOrDefault<double>();
  return Convert.ToDecimal(result);
}

4.   在Queries类中,添加下面的方法,该方法获取movies的价格平均值和directors列表:

View Code
public IEnumerable<NameAndPrice> GetAvgDirectorPrice()
{
  return _session.QueryOver<Movie>()
    .SelectList(list => list
      .SelectGroup(m => m.Director)
      .SelectAvg(m => m.UnitPrice)
    )
    .List<object[]>()
    .Select(props =>
      new NameAndPrice()
      {
        Name = (string)props[0],
        Price = Convert.ToDecimal(props[1])
      });
}

5.   在Program.cs中, 为RunQueries方法添加下述代码:

View Code
static void RunQueries(ISession session)
{
  var queries = new Queries(session);
  Show("Movie Price List:",
    queries.GetMoviePriceList());
  Show("Average Movie Price:",
    queries.GetAverageMoviePrice());
  Show("Average Price by Director:",
    queries.GetAvgDirectorPrice());
}

6.   编译运行,结果如下图所示:

原理

  让我们来逐一地来查看这些查询:

  • GetMoviePriceList 查询

  查询movie价格列表的代码如下:

View Code
_session.QueryOver<Movie>()
.Select(m => m.Name, m => m.UnitPrice)
.List<object[]>()
.Select(props =>
  new NameAndPrice()
  {
    Name = (string)props[0],
    Price = (decimal)props[1]
  });

  在这个查询中,我们想要返回一个包含movie名字和价格的列表.为了达成该目的,我们使用了QueryOver的Select方法从Movie对象中抓取了两个属性Name和UnitPrice. 在QueryOver结尾调用了List.因为我们返回了特定的属性值,而不是整个Movie对象.泛型参数指定了将返回一个对象的数组list,该list中的每个元素代表查询结果集中的一行,每个对象数组的第一个元素都是movie的Name属性.第二个元素是movie的UnitPrice属性.
  在Microsoft SQL Server中, 生成的SQL语句如下:

View Code
SELECT this_.Name      as y0_,
       this_.UnitPrice as y1_
FROM   Product this_
WHERE  this_.ProductType = 'Eg.Core.Movie'

  为了返回强类型的对象list,而不再返回这些对象的数组,我们使用了标准的LINQ to Objects:System.Linq中的Select来将查询结果放入整洁的NameAndPrice对象.

  • GetAverageMoviePrice query
View Code
_session.QueryOver<Movie>()
.Select(Projections.Avg<Movie>(m => m.UnitPrice))
.SingleOrDefault<double>();

  上面的代码中,查询了数据库中所有movies的平均价格.调用了聚合函数Projections.Avg,然后投影出结果.
  因为我们已经投影了一个聚合结果,我们可以调用.SingleOrDefault<double>()来执行查询和获得结果集.我们期望得到一个double类型的结果,然而由于我们处理的是货币,所以需要在将她返回给应用程序之前需要将其转换为decimal类型.
  在Microsoft SQL Server中, 生成的SQL语句如下:

View Code
SELECT avg(cast(this_.UnitPrice as DOUBLE PRECISION)) as y0_
FROM   Product this_
WHERE  this_.ProductType = 'Eg.Core.Movie'
  • GetAvgDirectorPrice 查询

  使用下面的代码,查询了movies的directors列表和平均价格:

View Code
_session.QueryOver<Movie>()
.Select(list => list
  .SelectGroup(m => m.Director)
  .SelectAvg(m => m.UnitPrice)
)
.List<object[]>()
.Select(props =>
  new NameAndPrice()
  {
    Name = (string)props[0],
    Price = Convert.ToDecimal(props[1])
  });

  这样的话,我们将投影Director属性和UnitPrice属性的平均值,并依据Director属性对结果集分组,代码如下:

View Code
.SelectList(list => list
  .SelectGroup(m => m.Director)
  .SelectAvg(m => m.UnitPrice)
)

  如同在第一个查询中所做的一样,我们返回了一个对象数组list,然后将使用LINQ to Objects将其转换为一个NameAndPrice对象list.
  在Microsoft SQL Server中, 生成的SQL语句如下:

View Code
SELECT   this_.Director                                as y0_,
         avg(cast(this_.UnitPrice as DOUBLE PRECISION)) as y1_
FROM     Product this_
WHERE    this_.ProductType = 'Eg.Core.Movie'
GROUP BY this_.Director
posted on 2012-07-25 13:35  迷恋弦哥  阅读(285)  评论(0编辑  收藏  举报