Linq-to-sql 使用 GroupBy 并返回满足条件的记录

Posted

技术标签:

【中文标题】Linq-to-sql 使用 GroupBy 并返回满足条件的记录【英文标题】:Linq-to-sql using GroupBy and return record satisfying condition 【发布时间】:2022-01-13 21:15:39 【问题描述】:

我有一个查询,我将提供它的相关部分

IQueryable<a> query;

query.Where(dbEntry => dbEntry.ConditionId == id)
    .Where(dbEntry => dbEntry.PharmacyStockBBD.Value > NO_BEFORE_THAN)
    .GroupBy(dbEntry => dbEntry.ProductId, pair => pair, (_e1, _e2) => new
    
        ProductId = _e1,
        Entry = _e2.OrderBy(pair => pair.PharmacyStockBBD).First()
    )
    .ToListAsync();

我来了

System.InvalidOperationException: The LINQ expression '(GroupByShaperExpression:
KeySelector: (p.Id), 
ElementSelector:new  
    PharmacyStockId = (ProjectionBindingExpression: PharmacyStockId), 
    PharmacyStockBBD = (ProjectionBindingExpression: PharmacyStockBBD), 
    ProductId = (ProjectionBindingExpression: ProductId), 
    ProductName = (ProjectionBindingExpression: ProductName), 
    ChildProductId = (ProjectionBindingExpression: ChildProductId), 
    IcnId = (ProjectionBindingExpression: IcnId), 
    IcnName = (ProjectionBindingExpression: IcnName), 
    PharmacyStock_ProductBoxes = (ProjectionBindingExpression: PharmacyStock_ProductBoxes), 
    .....
 
)
    .OrderBy(pair => pair.PharmacyStockBBD)' could not be translated. Either rewrite the query in a form that can be translated,

或通过插入调用显式切换到客户端评估 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync()。见https://go.microsoft.com/fwlink/?linkid=2101038 更多信息。

我要做的是按 ProductId 分组,但只获取 PharmacyStockBBD 为 Min 的记录。

我已经走了

Entry = _e2.Min(pair => pair.PharmacyStockBBD)

可行,但我需要整个 _e2。

我还知道 GroupBy 将在 sql 引擎 (MSSSQL) 上执行,我也知道它需要一些聚合函数,但我需要 PharmacyStockBBD 最小的整个记录​​集。

【问题讨论】:

GroupBy 将在 sql 引擎上执行实际上该特定查询不会在数据库中执行,这就是错误的症结.. 你能提供更多的上下文吗?也许我可以使用一个例子? 这个错误的意思是“你写的查询不能被翻译成sql并在db服务器上运行,所以你的选择是用可以翻译成sql的方式重写它,或者下载所有的数据从 db 服务器出来,然后 LINQ 将遍历它并在 c# 中进行分组”。在过去,后者是自动发生的,这是相当可怕的 顺便说一句,这不是 linq-to-sql;这是 EF 前身的名称;这是英孚 【参考方案1】:

我认为最有效的方法是使用原始 sql;

    context.YourTable.FromSqlInterpolated(@"
SELECT * 
FROM
(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY ProductId ORDER BY PharmacyStockBBD) rn
  FROM YourTable
  WHERE 
    PharmacyStockId > NO_BEFORE_THAN
) x
WHERE rn = 1")

您可以在此基础上进行撰写(包括更多表格等

我不确定您要在哪里进行 ConditionId 检查;它的确有所作为。如果您在内部查询中执行此操作,那么您将找到该条件的所有产品,然后从 1 开始对它们进行编号并找到该条件下的最小产品。如果您在外部查询中执行此操作,您将找到所有产品,无论条件如何,对它们进行编号,然后丢弃所有不在条件中的产品。你把它放在哪里取决于第一个产品是否会处于你想要的状态

本质上,你是要“过滤条件,然后取第一个” -> 把它放在里面 where ,还是要“取所有第一个,然后过滤它们作为条件” -> 把它放在里面外面的地方

【讨论】:

以上是关于Linq-to-sql 使用 GroupBy 并返回满足条件的记录的主要内容,如果未能解决你的问题,请参考以下文章

使用 Linq-to-SQL 的 ADO.NET 数据服务

使用 linq-to-sql 进行批量插入

使用 SQL Server Compact Edition 的 Linq-to-SQL

如何改进 Linq-To-Sql 代码

如何将 LINQ-to-SQL 映射到 BLL 类?

使用 LINQ-to-SQL 返回已过滤子对象的对象