EF Core:其中子句,用于检查是否至少有一个字符串列包含数组中的所有值



要在实体上实现基本的搜索功能,我想检查多个字段中的至少一个包含所有提供的搜索词。

为了说明这一点,假设我的实体是一个具有两个字符串字段的Furniture,名为NameDescription,并且我的数据库中有以下条目:

ID | Name           |  Description
---|----------------|------------
1  | Black chair 1  | Black chair
->  2  | Red chair 1    | Crimson chair
->  3  | Red chair 2    | Dark red chair
->  4  | Black chair 2  | Black straight back chair, red cushion
5  | Blue sofa      | Blue sofa
6  | Red sofa       | Red sofa

并且我想检索任何字段包含两个单词redchair的所有实体(所以这里是 2、3 和 4(。

我可以这样写:

var search = new[] { "red", "chair" };
var filtered = _db.Furnitures.AsNoTracking().Where(f => {
search.All(s => f.Name.ToLower().Contains(s)) 
|| search.All(s => f.Description.ToLower().Contains(s))
});

但 EF Core 警告我,这不能转换为 SQL,并且将在本地进行评估。

有什么方法可以编写此查询以便在SQL中对其进行评估?

注意:这是我面临的问题的简化示例,该模型显然很荒谬,因此请不要建议更改我的实体:)

您可以创建一些条件作为 LINQ 语句之外的表达式,然后将它们分别应用于查询:

var search = new[] { "red", "chair" };
var criteria = search.Select(s => (Expression<Func<Furniture, bool>>)(f => f.Name.ToLower().Contains(s) || f.Description.ToLower().Contains(s)))
.ToList();
var query = criteria.Aggregate(
_db.Furnitures.AsNoTracking().AsQueryable(),
(query, criterion) => query.Where(criterion));

对于更高级的情况(例如OR而不是AND(,您可能需要执行一些表达式树操作,如我在此处所述。

var search = new[] { "red", "chair" };
var criteria = search.Select(s => (Expression<Func<Furniture, bool>>)(f => f.Name.ToLower().Contains(s) || f.Description.ToLower().Contains(s)))
.ToList();
var query = _db.Furnitures.AsNoTracking().
.Where(Join(Expression.And, criteria));

有什么方法可以编写此查询以便在SQL中对其进行评估吗?

最好的选择是使用您自己编写的原始查询。

没有什么比使用原始查询从 SQL 数据库中选择数据更快、更灵活的了。它为您提供了您想要的内容,并避免了在运行时处理和翻译表达式的开销。

最新更新