Group by 在LINQ GroupBy中使用方法
我正在尝试操作要在字典中使用的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() })
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中遇到了一个错误,但这不会阻止我;-))非常感谢你!