【发布时间】:2021-10-14 15:49:41
【问题描述】:
我有 C# 应用程序 (.NET Core 3.1),并且我编写了以下 LINQ 表达式。
public ActionResult<bool> GetItems(string title)
{
var items = _service.All.GetItems().OrderByDescending(o => o.Id).Where(w => w.Portal_Id == 1);
if (!string.IsNullOrWhiteSpace(title))
{
var terms = title.Split(' ').ToList();
items = items.Where(w => terms.Any(a => w.ItemName.Contains(a)));
}
// Some Other code
return Ok();
}
每当执行此表达式时,我都会收到以下错误
The LINQ expression 'DbSet<PosItem>\r\n .Where(p => !(p.IsDeleted))\r\n
.OrderByDescending(p => p.CreatedAt)\r\n .Where(p => p.Portal_Id == 1)\r\n .Where(p => __terms_1\r\n
.Any(a => p.ItemName.Contains(a)))' could not be translated.
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().
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."
我无法添加 ToList() 并切换到客户端评估,因为数据集太大而无法这样做。
请告知如何在不切换到客户评估的情况下解决此问题。
谢谢
【问题讨论】:
-
某些函数调用可以根据这个table翻译成SQL。在您的特定情况下并且没有任何编码,我认为您需要的问题是
items.Where(w => terms.Any(a => w.ItemName.Contains(a)))。您正在测试一个客户端数组。 -
可能无法翻译
terms.Any()。您可以使用ExpressionBuilder和for/foreach 创建Expression,然后在items.Where(your_new_expression)中使用新创建的Expression -
这个答案有一个例子告诉你如何做到这一点How to create an Expression builder in .NET
-
很可能它不起作用,因为 Contains 方法
-
您提到数据很大,因此您希望避免进行任何客户端处理。正如这里多处所指出的,使用
Contains()将在最终的SQL 查询中产生一个或多个LIKE '%item%'术语。反过来,这可以很容易地在服务器上作为table scan 执行。这可能值得,也可能不值得。
标签: c# entity-framework linq .net-core