使用 IQueryable 创建动态查询

本文关键字:查询 动态 创建 IQueryable 使用 | 更新日期: 2023-09-27 18:31:00

我正在尝试迭代字符串数组并动态创建IQueryable查询。这很简单,但这就是我被困住的地方

var query = context.QuestionsMetaDatas.AsQueryable();
var keywords=new List<string>(){ "Test1","Test2" };
foreach(var key in keywords)
{
   query=query.Where(a=>a.Text.Contains(key));
}

现在的问题是,当查询生成时,它的编译为

select * from QuestionsMetaDatas where Text Like "Test1" AND Text Like "Test2"

而不是AND我希望查询生成OR......现在我该如何实现这一点?

使用 IQueryable 创建动态查询

我像 Raphael 建议的那样使用了谓词生成器,它只是一个要包含在项目中的文件,然后您的示例变为:

var keywords=new List<string>(){ "Test1","Test2" };
var predicate = PredicateBuilder.False<QuestionsMetaDatas>();
foreach (var key in keywords)
{
  predicate = predicate.Or (a => a.Text.Contains (key));
}
var query = context.QuestionsMetaDatas.AsQueryable().Where(predicate);

生成要查找的 OR 查询。

你试过用另一种方式包含吗?

var keywords=new List<int>(){ "Test1","Test2" };
query=query.Where(a=>keywords.Contains(a));

这就像一个IN条款

您可以查看谓词生成器,或者构建自己的表达式(这里是在IQueryable<QuestionsMetadatas>上使用静态扩展方法的可能解决方案)

public static IQueryable<QuestionsMetaDatas> FilterText(this IQueryable<QuestionsMetaDatas> queryable, IEnumerable<string> keywords)
        {
            var entityType = typeof(QuestionsMetaDatas);
            var parameter = Expression.Parameter(entityType, "a");
            var containsMethod = typeof(string).GetMethod("Contains"
                                                           , new[] { typeof(string) });
            var propertyExpression = Expression.Property(parameter, "Text");
            Expression body = Expression.Constant(false);
            foreach (var keyword in keywords)
            {
                var innerExpression = Expression.Call(propertyExpression, containsMethod, Expression.Constant(keyword));
                body = Expression.OrElse(body, innerExpression);
            }
            var lambda = Expression.Lambda<Func<QuestionsMetaDatas, bool>>(body, new[] { parameter });
            return queryable.Where(lambda);
        }

lambda看起来像这样:

a => ((False OrElse a.Text.Contains("firstKeyWord")) OrElse a.Text.Contains("secondKeyWord"))

和用法是

var query = context.QuestionsMetaDatas.AsQueryable();
var keywords=new List<string>(){ "Test1","Test2" };
query = query.FilterText(keywords);

或更短

var query = context.QuestionsMetaDatas.AsQueryable().FilterText(new[]{"Test1", "Test2"});