【发布时间】:2020-10-15 21:36:00
【问题描述】:
using (var ctx = new StockContext())
{
var syms = new string[] { "foo", "bar" };
return ctx.Assets.Select(x => x.Symbol)
.Where(symbol => syms.Any(sym => symbol.Contains(sym)))
.ToArray(); // EXCEPTION: InvalidOperationException: The LINQ expression 'DbSet<Asset>() .Where(a => __syms_0 .Any(sym => a.Symbol.Contains(sym)))' 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.
}
using (var ctx = new StockContext())
{
var syms = new string[] { "foo", "bar" };
return ctx.Assets.Select(x => x.Symbol)
.Where(symbol => s.Contains(syms[0]))
.ToArray(); // WORKS FINE
}
请查看上面的代码。我认为这是一种很常见的做法,但我什至无法使第一个示例有效。
我想要实现的是第一个示例中的代码可以翻译成:
SELECT Symbol FROM Assets WHERE Symbol LIKE '%foo%' OR Symbol LIKE '%bar%'。怎么会异常运行?
附言我知道 PredicateBuilder 可以解决这个问题。但是,我可以通过原生 EF 代码实现如此简单的操作吗?提前致谢!
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0-preview.4.20220.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-preview.4.20220.10" />
【问题讨论】:
-
.Where(symbol => s.Contains(syms[0]) || s.Contains(syms[1]))是一个选项吗? -
@mjwills 是的,您的解决方案适用于静态尺寸
IEnumerable -
@mannok 在 LINQ to Entities 或 Line to Objects 中都不是
OR。这是一个带有Contains的Any操作。在 C# 或 SQL 中,它不会被视为多个ORs。 -
您确定不应该改用全文搜索吗? ORM 旨在将对象映射到关系结果,而不是充当 SQL 的替代品。
LIKE '%abc%'操作的开销非常,因为它不能使用任何索引来查找其他字符串中间的字符串。它必须扫描整个表。这就是 FTS 在各种数据库中提供的内容 -
@PanagiotisKanavos 我们应该考虑搜索的成本。不过,在此之前,我想我们应该知道为什么EF不能先编译这么常见的操作了。
标签: c# entity-framework .net-core orm ef-core-3.0