首页 > 解决方案 > 通过 lambdada 表达式在组中选择当前记录

问题描述

我有这个表 在此处输入图像描述 ,我想按lifeplusecaseId 字段分组并返回所有字段分组

我试过这个

   var query = db.ApplicantCenterDistance.GroupBy(a => a.LifeplusCaseId)
                    .Select(s => new {
                        Id = s.Key,      
                        MinDistance = s.Min(m => m.Distance),
                        Duration = s.Min(m => m.Duration),
                       items=s.ToList(),
                    
                    }).Where(x=>x.MinDistance!=" ").ToList();

但我遇到了一个问题:

"System.InvalidOperationException: 'The LINQ expression '(GroupByShaperExpression:
KeySelector: (a.LifeplusCaseId), 
ElementSelector:(EntityShaperExpression: "

我不知道如何返回所有记录。

错误是:

System.InvalidOperationException:'LINQ 表达式'(GroupByShaperExpression:KeySelector:(a.LifeplusCaseId),ElementSelector:(EntityShaperExpression:EntityType:ApplicantCenterDistance ValueBufferExpression:(ProjectionBindingExpression:EmptyProjectionMember)IsNullable:False)).ToList()'无法翻译。以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

标签: c#entity-frameworklinqlambda

解决方案


此类错误在旧版本的 EF 中很常见,我在 EF 6.4.4 中测试了此语法并没有发现任何问题,但是您的类型结构可能存在其他问题,这些问题可能会影响Linq to SQL表达式评估。

您的错误消息与 EF 6.4.4 命名法不匹配,这表明这里还有其他东西在起作用,但是此错误与 EF Core 3.1+ 匹配。

首先,由于错误是专门围绕您使用 的.ToList(),所以将其从表达式中删除,EF6 将支持通过返回分组表达式和投影AsEnumerable<>。以下任一项都适用于 EF6:

.Select(s => new {
    Id = s.Key,      
    MinDistance = s.Min(m => m.Distance),
    Duration = s.Min(m => m.Duration),
    items = s
})

或通过投影.AsEnumerable<ApplicantCenterDistance>()

.Select(s => new {
    Id = s.Key,      
    MinDistance = s.Min(m => m.Distance),
    Duration = s.Min(m => m.Duration),
    items = s.AsEnumerable<ApplicantCenterDistance>()
})

如果您仍然遇到问题,您还可以将过滤条件移动到投影之前,这允许在.ToList()客户端评估投影(以及之前的),这就是异常消息和相关的MS Docs 文章所暗示的内容:

var query = db.ApplicantCenterDistance
                .GroupBy(a => a.LifeplusCaseId)
                .Where(x => x.Where(x => x.Min(m => m.Distance) != " ")
                .Select(s => new {
                    Id = s.Key,      
                    MinDistance = s.Min(m => m.Distance),
                    Duration = s.Min(m => m.Duration),
                    items=s.ToList(),                    
                }).ToList();

更新:EF 核心

如果您在 EF Core 3.1+ 中执行此操作,则一种选择是将整个记录集拉到客户端的内存中,然后将其分组。如果无论如何结果的数量总是非常大,那么这不会产生太大影响,因为您已经将所有项目保留在每个组中:

var dataList = db.ApplicantCenterDistance.ToList();
var data = dataList
                .GroupBy(a => a.LifeplusCaseId)
                .Select(s => new {
                    Id = s.Key,      
                    MinDistance = s.Min(m => m.Distance),
                    Duration = s.Min(m => m.Duration),
                    items=s.ToList(),                    
                }).Where(x=>x.MinDistance!=" ").ToList();

更新:字符串字段的最小值

作为Distance一个字符串,MIN如果您实际上想要最小值,则可能无法评估正确的数字比较,为此您需要将其转换为数字类型。

注意:您可以在上述任何查询中使用此语法,但是如果您希望在数据库中执行评估,则需要转换为 a double,在最后一个客户端示例中,您可以使用您希望转换的任何 C# 代码价值。

MinDistance = s.Where(m => m != " ").Min(m => (double)m.Distance),

在这里,我们首先过滤掉不能转换为数字的值,您可能需要根据您的数据集是否包含空值或零长度字符串来调整它。有关更多详细信息,请参阅此帖子


推荐阅读