Group by 在LINQ GroupBy中使用方法

Group by 在LINQ GroupBy中使用方法,group-by,entity-framework-core,linq-to-entities,c#-8.0,Group By,Entity Framework Core,Linq To Entities,C# 8.0,我正在尝试操作要在字典中使用的GroupBy子句中的属性: var lifeStages = await _dbContext.Customers .GroupBy(x => GetLifeStage(x.DoB)) .Select(x => new { LifeStage = x.Key, Count = x.Count() })

我正在尝试操作要在字典中使用的GroupBy子句中的属性:

var lifeStages = await _dbContext.Customers
                                 .GroupBy(x => GetLifeStage(x.DoB))
                                 .Select(x => new { LifeStage = x.Key, Count = x.Count() })
                                 .ToDictionaryAsync(x => x.LifeStage, x => x.Count);
我期待这样的结果

青少年:10,, 成人:15, 高年级:12等

但是得到错误:

Either rewrite the query in a form that can be translated,
    or switch to client evaluation explicitly 
    by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). 
当然,我不能将ToDictionary()与上述任何调用结合起来,而分解查询并没有解决问题,也没有教会我任何东西)

我尝试过将GetLifeStage()设置为静态和异步,两者也没有区别。该方法被调用,执行它需要执行的操作,但仍然无法转换GroupBy

如果我省略Select()部分并使用GroupBy的键,则会出现相同的错误: “……无法翻译。”

我也看到了一个错误,说我无法在试用期间将GroupBy()与ToDictionary()组合,但似乎没有弹出atm

由于我的想法快用完了,欢迎提出所有建议

更新:

private LifeStage GetLifeStage(DateTimeOffset doB)
{
  var ageInMonths = Math.Abs(12 * (doB.Year - DateTimeOffset.UtcNow.Year) + doB.Month - DateTimeOffset.UtcNow.Month);

  switch (ageInMonths)
  {
    case < 216:
      return LifeStage.Adolescent;
    case < 780:
      return LifeStage.Adult;
    case >= 780:
      return LifeStage.Senior;
  }
}
private LifeStage GetLifeStage(DateTimeOffset-doB)
{
var ageInMonths=Math.Abs(12*(日期年-日期时间偏移量.UtcNow.Year)+日期月-日期时间偏移量.UtcNow.Month);
开关(以月计)
{
例<216:
回归人生阶段。青春期;
例<780:
成人期;
案例>=780:
返回生命舞台;
}
}

问题是在
GroupBy
表达式中使用了自定义的
GetLifeStage
方法。无法将自定义方法转换为SQL,因为查询转换器代码无法知道该方法内部的内容。它不能被调用,因为在翻译过程中根本没有对象

为了使其可翻译,您必须将自定义方法调用替换为其主体,转换为可翻译表达式-基本上可以用作表达式体方法。不能使用变量和开关,但可以使用条件运算符。可以使用中间投影(
Select
)代替变量

以下是等效的可翻译查询:

var lifeStages=await\u dbContext.Customers
.Select(c=>new{Customer=c,AgeInMonths=Math.Abs(12*(c.DoB.Year-DateTimeOffset.UtcNow.Year)+c.DoB.Month-DateTimeOffset.UtcNow.Month)})
.GroupBy(x=>x.AgeInMonths<216?寿命期。青少年:x.AgeInMonths<780?寿命期。成人:寿命期。老年人)
//其余部分与原件相同
.Select(x=>new{LifeStage=x.Key,Count=x.Count()})
.ToDictionaryAsync(x=>x.LifeStage,x=>x.Count);

“我尝试过将GetLifeStage()设置为静态和异步,两者没有区别。方法会被调用…”这就是问题所在-不会调用已转换的方法。查询转换器识别已知的方法,并将它们转换为相应的SQL语法,而不调用它们。这就是为什么自定义(未知)方法无法转换的原因。请记住,查询转换是在运行时进行的,翻译程序与其他任何程序一样是代码—它不是编译器,没有源代码,也看不到方法中的内容。@IvanStoev感谢您的清晰解释。因此,我的选择是编写自己的扩展Linq,或GroupBy DoB,然后在没有Linq的情况下处理字典数据?欢迎您。最好将
GetLifeStage
方法调用替换为内联可翻译表达式。如果您能够做到这一点,那么代码的其余部分就可以工作,而不需要修改。你能发布
GetLifeStage
方法主体来看看这是否可行吗?没有原始SQL,只有正则C#表达式。通常,
开关
可以替换为条件运算符(
condition1?result1:condition2?result2:…)
。但这里的问题是EF Core不支持
DateTimeOffset
成员的转换。如果属性类型是
DateTime
,则可以轻松地对其进行翻译。您的目标EF核心版本是什么?对不起,实际上EFC支持所需的
DateTimeOffset
properties/methods。非常感谢您的精彩解释!我被狠狠地踢了一顿,但你用一点知识弥补了这一切!我正在测试atm,正如您首先期望的,我确实在DateTimeOffset中遇到了一个错误,但这不会阻止我;-))非常感谢你!