【问题标题】:Using LINQ how do I have a grouping by a "calculated field"使用 LINQ 如何按“计算字段”进行分组
【发布时间】:2010-09-27 21:27:08
【问题描述】:

我正在使用 LINQ to EF 并有以下 LINQ 查询:

var results = (from x in ctx.Items
               group x by x.Year into decades
               orderby decades.Count() descending
               select new { Decade = decades.Key, DecadeCount = decades.Count() });

所以这种方式让我到达了我想去的地方,因为我得到了按年份细分的项目以及当年的项目数量。 (即 2001 - 10, 1975 - 15, 2005 - 5, 1976 - 1)我真正想做的事情是按十年分解它们(即 2000s - 15, 1970s - 16)。

如何在 Linq 语句的 group 子句的“by”部分中具有“计算字段”。我想我想要的基本上是这样的:

var results = (from x in ctx.Items
               group x by (x => x.Year.Value.ToString().Substring(0, 3) + "0s") into decades
               orderby decades.Count() descending
               select new { Decade = decades.Key, DecadeCount = decades.Count() });

或更一般的语法,以便我可以进行一些更复杂的评估/计算来进行分组。有什么想法吗?

编辑(更新):

(x => x.Year.Value.ToString().Substring(0, 3) + "0s") - 不起作用 - "LINQ to Entities 无法识别方法 'System.String ToString() ' 方法,并且这个方法不能翻译成 store 表达式。”

(x.Year / 10 * 10) - 功能有效(谢谢) - 唯一的“问题”是 's' 不在末尾(即 1970 与 1970 年代)

有没有在 by 子句中放置一个函数?即按 this.ManipulateYear(x.Year) 将 x 分组为几十年...或... x => x.Year.Value.ToString().Substring(0,3) + "0s" ??最好有一些技术(例如调用函数或使用 lambda 表达式),这样我就可以涵盖我能想到的任何情况。

再次感谢大家对此的帮助。

【问题讨论】:

    标签: c# .net linq .net-3.5 linq-to-entities


    【解决方案1】:

    我相信您会将 SelectMany 方法链接到结果的末尾。这将返回 IEnumerable 的 IEnumerable。

    【讨论】:

    • 不,分组已经是 IEnumerable 的 IEnumerable(因为 IGrouping 扩展了 IEnumberable)。这里不需要 SelectMany。
    【解决方案2】:

    按 x.Year/10 分组怎么样? (还没有测试过!)

    var results = (from x in ctx.Items
                   group x by (x.Year / 10 * 10) into decades
                   orderby decades.Count() descending
                   select new { Decade = decades.Key, DecadeCount = decades.Count() });
    

    EDIT1:将 (x.Year / 10) 更改为 (x.Year / 10 * 10) 以获取例如 1980 而不是 198。

    EDIT2:在您的示例中,“将 x 按 x.Year.Value.ToString().Substring(0, 3) + "0s") 分组为几十年”也应该有效。不需要lamba语法。

    EDIT3:删除了一个额外的 * 10。谢谢 Marc!

    【讨论】:

    • 在 LINQ-to-Objects 中应该没问题。使用 EF,您需要仔细检查算术的计算方式(int/float/etc)。例如,您可能需要 Math.Floor(x.Year/10) * 10 - 假设 EF 可以将 Math.Floor 映射到 TSQL 的 FLOOR
    • 哦,你可能有两次 *10(一次在group,一次在select new
    • .ToString() 不起作用(无法映射到 SQL 类型错误) - 我没有测试过“数学”解决方案,但它似乎可以解决这种情况。我想知道如何在所有情况下(即没有数学类型的解决方案或需要一系列 if 语句或类似的解决方案)。
    【解决方案3】:

    您可以使用let 子句来避免多次计算十年:

    from x in ctx.Items
    group x by (x.Year / 10 * 10) into decades
    let decadeCount = decades.Count()
    orderby decadeCount descending
    select new { Decade = decades.Key, DecadeCount = decadeCount }
    

    【讨论】:

    • 好点。它可能不会对 LINQ to SQL 产生影响,但肯定会在 LINQ to Objects 中为您节省一个额外的 Count()。
    【解决方案4】:

    看起来我们无法对实体框架的部分类中定义的计算字段进行分组或选择或类似操作。

    计算的字段可用于 LINQ to 对象(因此您可以将所有数据作为对象返回,然后进行分组)

    【讨论】:

      猜你喜欢
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      • 2022-07-21
      相关资源
      最近更新 更多