【问题标题】:EF Core: where clause to check if at least one string column contains all values in an arrayEF Core:where 子句检查是否至少一个字符串列包含数组中的所有值
【发布时间】:2021-06-02 04:05:17
【问题描述】:

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

为了说明,假设我的实体是一个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 中对其进行评估?

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

【问题讨论】:

  • 一般情况下,当 C# 函数没有对应的 SQL 翻译时,会出现此警告消息。我在Entity Framework 6 中测试过,这可行,但不确定为什么在 EF Core 中不起作用。也许 EF Core 无法将.All 函数与相应的数据库函数进行转换。

标签: c# entity-framework-core


【解决方案1】:

您可以在 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),您可能需要进行一些表达式树操作,正如我所描述的here

    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));

【讨论】:

    【解决方案2】:

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

    最好的选择是使用您自己编写的raw query

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

    【讨论】:

    • 如果可能的话,我想避免用 C# 编写 SQL,但我可能会编写一个存储过程。感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多