首页 > 解决方案 > 拆分后如何使用实体框架搜索文本?

问题描述

我有一个实体模型

public class User{
   public string FirstName {get;set;}
   public string LastName {get;set;}
   public string Department {get;set;}
}

所以我想"john smith"使用实体框架核心 3.1 在数据库中搜索文本。

我之前正在拆分文本。

    public async Task<IEnumerable<UserListViewModel>> Search(string search)
    {
        var terms = search.Split(" ");

        var queryable = _context.Users.Where(s => terms.All(m => s.Department.ToLower().Contains(m)) ||
                                                  terms.All(m => s.FirstName.ToLower().Contains(m)) ||
                                                  terms.All(m => s.LastName.ToLower().Contains(m))).AsQueryable();

        ...........
        ...........
        ...........
    }

但它不起作用。

那么我该怎么做呢?

标签: c#entity-frameworklinqentity-framework-coreentity-framework-core-3.1

解决方案


EF Core 3.x 在大多数情况下并不真正支持 and 的翻译AllAny而且您的代码略有错误,我认为您真正想要的是:

var queryable = _context.Users.Where(u => terms.All(m => u.Department.Contains(m) ||
                                                         u.FirstName.Contains(m) ||
                                                         u.LastName.Contains(m)));

由于无法翻译,因此您需要将其重新格式化为可以翻译的代码。

使用LINQKit,您可以创建一个扩展,将查询重新映射到每个术语PredicateBuilder的一系列测试中:&&

// searchTerms - IEnumerable<TKey> where all must be in a row's key
// testFne(row,searchTerm) - test one of searchTerms against a row
// dbq.Where(r => searchTerms.All(s => testFne(r,s)))
public static IQueryable<T> WhereAll<T,TKey>(this IQueryable<T> dbq, IEnumerable<TKey> searchTerms, Expression<Func<T, TKey, bool>> testFne) {
    var pred = PredicateBuilder.New<T>();
    foreach (var s in searchTerms)
        pred = pred.And(r => testFne.Invoke(r, s));

    return dbq.Where((Expression<Func<T,bool>>)pred.Expand());
}

你会使用这样的:

var queryable = _context.Users
                    .WhereAll(terms,
                              (u,m) => u.Department.Contains(m) ||
                                       u.FirstName.Contains(m) ||
                                       u.LastName.Contains(m));

对于“john smith”,扩展方法将创建等价于:

var queryable = _context.Users
                    .Where(u => (u.Department.Contains("john") ||
                                 u.FirstName.Contains("john") ||
                                 u.LastName.Contains("john")) &&
                                (u.Department.Contains("smith") ||
                                 u.FirstName.Contains("smith") ||
                                 u.LastName.Contains("smith"))
                           );

推荐阅读