动态LINQ在IQueryable上聚合为单个查询 [英] Dynamic LINQ aggregates on IQueryable as a single query

查看:53
本文介绍了动态LINQ在IQueryable上聚合为单个查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个适用于通用IQueryable数据源的数据网格库.在底部,选定的列将具有汇总:总和,平均值,计数等.

I'm building a datagrid library that works on generic IQueryable data sources. At the bottom selected columns will have aggregates: sum, average, count etc.

我可以使用本文我不想为数据源单独运行它们,因为这会导致对数据库的多个查询,我宁愿创建单个表达式树,并将其作为单个查询执行.

I don't want to run them individually for a datasource, as this would cause multiple queries on the database, I would rather create a single expression tree an execute this as a single query.

在静态LINQ中,您将执行所有.Sum,.Average和.Count方法,并返回带有值的新匿名类型.我不需要匿名类型(除非这是唯一的方法):聚合的列表或数组都可以.

In static LINQ you'd do all the .Sum, .Average and .Count methods and return a new anonymous type with the values. I don't need an anonymous type (unless this is the only way): a list or array of the aggregates would be fine.

我从另一篇文章中假设,我将需要以某种方式将一系列MethodCallExpression对象串在一起.有人可以帮忙吗?

I assume from the other article I would need to string together a series of MethodCallExpression objects somehow. Can anyone help?

推荐答案

我找到了另一种方法,该方法使用动态LINQ库,避免了构建复杂的表达式树.

I found an alternative approach which uses the Dynamic LINQ library and avoids having to construct convoluted expression trees.

该解决方案在下面的单元测试中,适用于任何有兴趣的人.我有一个名为TestQueryableDataset的随机数据集.此IQueryable数据源的通用类型具有Total属性(十进制),Discount属性(可空十进制)和ID属性(int).

The solution is in the unit test below for anyone who is interested. I have a random dataset called TestQueryableDataset. The generic type of this IQueryable datasource has a Total property (decimal), a Discount property (nullable decimal) and an ID property (int).

单元测试首先使用静态LINQ查询获得预期结果.

The unit test gets the expected results first, using static LINQ queries.

然后构造一个选择语句,该语句使用groupby变量"it"来计算总和,平均值和计数.属性名称通过字符串传递,以证明它是字符串类型的.

It then constructs a select statement that uses the groupby variable 'it' to compute the sum, average and count. The property names are passed in by string to demonstrate this is stringly-typed.

分组方法 .GroupBy(x => 1)是一个虚拟分组,可用于将汇总应用于整个数据集.

The group-by method .GroupBy(x=> 1) is a dummy grouping to enable the aggregates to apply to the whole dataset.

请注意,这将返回具有属性t0,t1和t2的单个动态结果.但是,groupby/select操作仍返回一个IQueryable,但结果为单个.我们必须使用t.Cast().First();转换为对象数组,然后得到第一个结果.

Note that this returns a single dynamic result with properties t0, t1 and t2. However, the groupby/select operation still returns an IQueryable but with a single result. We have to use the t.Cast().First(); to convert to an array of object, then get the first result.

然后我们可以使用反射将每个结果(t0,t1,t2)的属性作为实际值,并断言它们与我们之前获得的静态结果相匹配.

We can then use reflection to get the properties of each result (t0, t1, t2) as the actual values and assert that they match the static result we got earlier.

    [TestMethod()]
    [TestProperty("Anvil.DataSets", "QueryableExtensions")]
    public void DynamicAggregate_test()
    {
        var source = new Anvil.Test.DataSets.TestQueryableDataset();

        var data = source.GetData();

        var expectedTotal = (from d in data select d.Total).Sum();
        var expectedDiscount = (from d in data select d.Discount).Average();
        var expectedCount = (from d in data select d.ID).Count();

        const string prop0 = "Total";
        const string prop1 = "Discount";
        const string prop2 = "ID";

        string sumExpr = string.Format("new ( Sum(it.{0}) as t0, Average(it.{1}) as t1 , Count() as t2)", prop0,prop1, prop2);
        var t = data.GroupBy(x => 1).Select(sumExpr);

        var firstItem = t.Cast<object>().First();

        var ttype = firstItem.GetType();
        var p0 = ttype.GetProperty("t0");
        var p1 = ttype.GetProperty("t1");
        var p2 = ttype.GetProperty("t2");

        decimal actualTotal = (decimal)(p0.GetValue(firstItem));
        decimal actualDiscount = (decimal)(p1.GetValue(firstItem));
        int actualCount = (int)(p2.GetValue(firstItem));

        Assert.AreEqual(expectedTotal, actualTotal);
        Assert.AreEqual(expectedDiscount, actualDiscount);
        Assert.AreEqual(expectedCount, actualCount);
    }

另请参阅:

  • Dynamic Linq GroupBy
  • System.LINQ.Dynamic: Select(" new (...)") into a List<T> (or any other enumerable collection of <T>)
  • http://developergems.blogspot.co.uk/2012/02/group-by-with-dynamic-linq.html

这篇关于动态LINQ在IQueryable上聚合为单个查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆