C# 如何使用实体框架查找所有搜索词都包含在选定列中的行

C# 如何使用实体框架查找所有搜索词都包含在选定列中的行,c#,entity-framework,linq,linq-to-entities,entity-framework-6,C#,Entity Framework,Linq,Linq To Entities,Entity Framework 6,就上下文而言,这个问题与和有关。在这种情况下,用户可以指定短语数组。我想通过询问如何创建一种通用方法来查找实体,其中任何短语的所有单词都包含在任何指定的列中,从而进一步扩展 为了让您更好地了解我所说的内容,如果我将此作为非泛型方法编写,它将如下所示: var searchPhrases = new [] {"John Smith", "Smith Bob"}; var searchTermSets = searchPhrases.Select(x => x.Split(new[] { '

就上下文而言,这个问题与和有关。在这种情况下,用户可以指定短语数组。我想通过询问如何创建一种通用方法来查找实体,其中任何短语的所有单词都包含在任何指定的列中,从而进一步扩展

为了让您更好地了解我所说的内容,如果我将此作为非泛型方法编写,它将如下所示:

var searchPhrases = new [] {"John Smith", "Smith Bob"};
var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm))));
contact.WhereIn(
    searchPhrases,
    c => c.FullName,
    c => c.FirstName,
    c => c.LastName);
IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
public static class QueryableExtensions
{
    public static IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
    {
        var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        var c = Expression.Parameter(typeof(T), "c");
        var searchTerms = Expression.Parameter(typeof(string[]), "searchTerms");
        var searchTerm = Expression.Parameter(typeof(string), "searchTerm");
        var allCondition = propertySelectors
            .Select(propertySelector => (Expression)Expression.Call(
                propertySelector.Body.ReplaceParameter(propertySelector.Parameters[0], c),
                "Contains", Type.EmptyTypes, searchTerm))
            .Aggregate(Expression.OrElse);
        var allPredicate = Expression.Lambda<Func<string, bool>>(allCondition, searchTerm);
        var allCall = Expression.Call(
            typeof(Enumerable), "All", new[] { typeof(string) }, 
            searchTerms, allPredicate);
        var anyPredicate = Expression.Lambda<Func<string[], bool>>(allCall, searchTerms);
        var anyCall = Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(string[]) },
            Expression.Constant(searchTermSets), anyPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(anyCall, c);
        return source.Where(predicate);
    }
}
我想做的是做一个扩展方法,在这里我可以做如下事情:

var searchPhrases = new [] {"John Smith", "Smith Bob"};
var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm))));
contact.WhereIn(
    searchPhrases,
    c => c.FullName,
    c => c.FirstName,
    c => c.LastName);
IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
public static class QueryableExtensions
{
    public static IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
    {
        var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        var c = Expression.Parameter(typeof(T), "c");
        var searchTerms = Expression.Parameter(typeof(string[]), "searchTerms");
        var searchTerm = Expression.Parameter(typeof(string), "searchTerm");
        var allCondition = propertySelectors
            .Select(propertySelector => (Expression)Expression.Call(
                propertySelector.Body.ReplaceParameter(propertySelector.Parameters[0], c),
                "Contains", Type.EmptyTypes, searchTerm))
            .Aggregate(Expression.OrElse);
        var allPredicate = Expression.Lambda<Func<string, bool>>(allCondition, searchTerm);
        var allCall = Expression.Call(
            typeof(Enumerable), "All", new[] { typeof(string) }, 
            searchTerms, allPredicate);
        var anyPredicate = Expression.Lambda<Func<string[], bool>>(allCall, searchTerms);
        var anyCall = Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(string[]) },
            Expression.Constant(searchTermSets), anyPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(anyCall, c);
        return source.Where(predicate);
    }
}
扩展方法签名将如下所示:

var searchPhrases = new [] {"John Smith", "Smith Bob"};
var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm))));
contact.WhereIn(
    searchPhrases,
    c => c.FullName,
    c => c.FirstName,
    c => c.LastName);
IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
public static class QueryableExtensions
{
    public static IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
    {
        var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        var c = Expression.Parameter(typeof(T), "c");
        var searchTerms = Expression.Parameter(typeof(string[]), "searchTerms");
        var searchTerm = Expression.Parameter(typeof(string), "searchTerm");
        var allCondition = propertySelectors
            .Select(propertySelector => (Expression)Expression.Call(
                propertySelector.Body.ReplaceParameter(propertySelector.Parameters[0], c),
                "Contains", Type.EmptyTypes, searchTerm))
            .Aggregate(Expression.OrElse);
        var allPredicate = Expression.Lambda<Func<string, bool>>(allCondition, searchTerm);
        var allCall = Expression.Call(
            typeof(Enumerable), "All", new[] { typeof(string) }, 
            searchTerms, allPredicate);
        var anyPredicate = Expression.Lambda<Func<string[], bool>>(allCall, searchTerms);
        var anyCall = Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(string[]) },
            Expression.Constant(searchTermSets), anyPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(anyCall, c);
        return source.Where(predicate);
    }
}
IQueryable其中(此IQueryable源、IEnumerable搜索短语、参数表达式[]属性选择器)

我试着按照前面的问题中的相同模式,但我没有走多远。对
All()
的调用把我绊倒了。

表达式就像

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm)))); 
可以使用
表达式动态生成。调用
可枚举。任何
可枚举。所有

首先,我们需要一个简单的参数替换程序,以便将所有传递的
表达式
绑定到单个参数:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}
然后实现可以如下所示:

var searchPhrases = new [] {"John Smith", "Smith Bob"};
var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm))));
contact.WhereIn(
    searchPhrases,
    c => c.FullName,
    c => c.FirstName,
    c => c.LastName);
IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
public static class QueryableExtensions
{
    public static IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
    {
        var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        var c = Expression.Parameter(typeof(T), "c");
        var searchTerms = Expression.Parameter(typeof(string[]), "searchTerms");
        var searchTerm = Expression.Parameter(typeof(string), "searchTerm");
        var allCondition = propertySelectors
            .Select(propertySelector => (Expression)Expression.Call(
                propertySelector.Body.ReplaceParameter(propertySelector.Parameters[0], c),
                "Contains", Type.EmptyTypes, searchTerm))
            .Aggregate(Expression.OrElse);
        var allPredicate = Expression.Lambda<Func<string, bool>>(allCondition, searchTerm);
        var allCall = Expression.Call(
            typeof(Enumerable), "All", new[] { typeof(string) }, 
            searchTerms, allPredicate);
        var anyPredicate = Expression.Lambda<Func<string[], bool>>(allCall, searchTerms);
        var anyCall = Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(string[]) },
            Expression.Constant(searchTermSets), anyPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(anyCall, c);
        return source.Where(predicate);
    }
}

类似谓词的表达式

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm)))); 
可以使用
表达式动态生成。调用
可枚举。任何
可枚举。所有

首先,我们需要一个简单的参数替换程序,以便将所有传递的
表达式
绑定到单个参数:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}
然后实现可以如下所示:

var searchPhrases = new [] {"John Smith", "Smith Bob"};
var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

contacts.Where(c =>
    searchTermSets.Any(searchTerms =>
        searchTerms.All(searchTerm =>
            c.FullName.Contains(searchTerm)
            || c.FirstName.Contains(searchTerm)
            || c.LastName.Contains(searchTerm))));
contact.WhereIn(
    searchPhrases,
    c => c.FullName,
    c => c.FirstName,
    c => c.LastName);
IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
public static class QueryableExtensions
{
    public static IQueryable<T> WhereIn<T>(this IQueryable<T> source, IEnumerable<string> searchPhrases, params Expression<Func<T, string>>[] propertySelectors)
    {
        var searchTermSets = searchPhrases.Select(x => x.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        var c = Expression.Parameter(typeof(T), "c");
        var searchTerms = Expression.Parameter(typeof(string[]), "searchTerms");
        var searchTerm = Expression.Parameter(typeof(string), "searchTerm");
        var allCondition = propertySelectors
            .Select(propertySelector => (Expression)Expression.Call(
                propertySelector.Body.ReplaceParameter(propertySelector.Parameters[0], c),
                "Contains", Type.EmptyTypes, searchTerm))
            .Aggregate(Expression.OrElse);
        var allPredicate = Expression.Lambda<Func<string, bool>>(allCondition, searchTerm);
        var allCall = Expression.Call(
            typeof(Enumerable), "All", new[] { typeof(string) }, 
            searchTerms, allPredicate);
        var anyPredicate = Expression.Lambda<Func<string[], bool>>(allCall, searchTerms);
        var anyCall = Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(string[]) },
            Expression.Constant(searchTermSets), anyPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(anyCall, c);
        return source.Where(predicate);
    }
}

为什么不在模型中创建一个计算属性并连接所有搜索字段,这样就不需要多个表达式了
publicstringsearchfields=>$“{FullName}{FirstName}{LastName}”
?我不知道您的数据库中有多少记录,但您想炸毁服务器。。。这正是可以做到这一点的查询:)为什么不在模型中创建一个计算属性并连接所有搜索字段,那么就不需要多个表达式了
publicstringsearchfields=>$“{FullName}{FirstName}{LastName}”
?我不知道您的数据库中有多少记录,但您想炸毁服务器。。。这正是可以做到这一点的查询:)