在 LINQ GroupBy 中使用方法
Use method inside LINQ GroupBy
我正在尝试操作要在字典中使用的 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;
}
}
问题是 custom GetLifeStage
方法在 GroupBy
expression 中的使用。自定义方法无法转换为 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);
我正在尝试操作要在字典中使用的 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;
}
}
问题是 custom GetLifeStage
方法在 GroupBy
expression 中的使用。自定义方法无法转换为 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);