问题描述
我正在尝试操纵要在字典中使用的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;
}
}
解决方法
问题是在GetLifeStage
表达式中使用了 custom GroupBy
方法。自定义方法无法转换为SQL,因为查询翻译器代码无法知道该方法内部的内容。它不能被调用,因为在翻译过程中根本没有对象。
为了使其可翻译,您必须用其主体替换自定义方法调用,并将其转换为可翻译的表达式-基本上可以用作表达式合并方法。您不能使用变量和切换,但可以使用条件运算符。可以使用中间投影(Select
)来代替变量。
以下是等效的可翻译查询:
var lifeStages = await _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 ? LifeStage.Adolescent : x.AgeInMonths < 780 ? LifeStage.Adult : LifeStage.Senior)
// the rest is the same as original
.Select(x => new { LifeStage = x.Key,Count = x.Count() })
.ToDictionaryAsync(x => x.LifeStage,x => x.Count);