Her*_*rdy 2 linq search predicate where
我想使用谓词构建自定义 linq 查询。
而不是使用静态Where子句,即...
public IEnumerable<Entities.BusinessDirectory.BDEntity> Search(string searchExpression)
{
var db = new ApplicationDbContext();
return db.BDEntities
.Where(x => searchExpression.Split(' ').Any(y => x.Value.Contains(y)));
}
Run Code Online (Sandbox Code Playgroud)
...我正在使用泛型方法扩展 DbContext Search(predicate, searchExpression),它与静态方法具有相同的效果(见上文)
public static class DbContextExtensions
{
public static IEnumerable<T> Search<T>(
this DbSet<T> dbSet,
Expression<Func<T, object>> predicate,
string searchExpression)
where T : class, new()
{
//Experimental
return dbSet
.Where(x => searchExpression.Split(' ').Any(y => predicate.Contains(x)));
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到以下错误:
错误 6 实例参数:无法从“System.Linq.Expressions.Expression>”转换为“System.Linq.ParallelQuery” Extensions.cs
简单的答案是,您可以在查询Where子句中添加一个谓词,请记住,Where谓词的定义是它返回bool。最终,您的表达式必须是一个boolean表达式才能添加到Where子句中。
Expression<Func<BDEntity, bool>> predicate = (BDEntity entity) => entity.Field == "TEST";
var query = context.BDEntities;
if (predicate != null)
query = query.Where(predicate);
// expand to get the results.
var results = query.ToList();
Run Code Online (Sandbox Code Playgroud)
如果您需要像_ => _.MyFieldValue == "TEST"在运行时那样构建表达式,那就有点棘手了。
给定一个谓词_ => _.DatabaseField和一个字符串值"TEST",创建一个适合实体框架的表达式来创建一个where测试谓词的子句。
此方法将构建适当的Equal表达式。
public static Expression<Func<T, bool>> BuildEqualPredicate<T>(
Expression<Func<T, string>> memberAccessor,
string term)
{
var toString = Expression.Convert(Expression.Constant(term), typeof(string));
Expression expression = Expression.Equal(memberAccessor.Body, toString);
var predicate = Expression.Lambda<Func<T, bool>>(
expression,
memberAccessor.Parameters);
return predicate;
}
Run Code Online (Sandbox Code Playgroud)
以下断言将通过:
var expression = Predicate.BuildEqualPredicate<MyDbEntity>(_ => _.DatabaseField, "TEST");
expression.Compile()
.Invoke(new MyDbEntity { DatabaseField = "TEST" })
.Should().BeTrue();
expression.Compile()
.Invoke(new MyDbEntity { DatabaseField = "ANOTHERVALUE"})
.Should().BeFalse();
Run Code Online (Sandbox Code Playgroud)
通过在 where 子句中包含谓词,实体框架可以使用谓词。
var predicate = PredicateExtensions.BuildEqualPredicate<MyDbEntity>(
_ => _.DatabaseField,
"TEST");
var results = context.DbEntity.Where(predicate).ToList();
Run Code Online (Sandbox Code Playgroud)
您可以对成员表达式做更多的事情,例如使用StartsWith和Contains创建更复杂的谓词。
Expression<Func<T, string>> memberAccessor = _ => _.DBEntityField;
Run Code Online (Sandbox Code Playgroud)
您可以像这样动态地创建一个谓词,在这个例子中它创建一个谓词来检查一个字符串是否是StartsWith一个特定的值,or is null。
private Expression<Func<T, bool>> BuildPredicate(
string term,
Expression<Func<T, string>> memberAccessor)
{
var startsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var isNull = typeof(string).GetMethod("IsNullOrEmpty", new[] { typeof(string) });
var toString = Expression.Convert(Expression.Constant(term), typeof(string));
Expression expression = Expression.Call(
memberAccessor.Body,
startsWith,
new Expression[] { toString });
expression = Expression.Or(expression, Expression.Call(
isNull,
toString));
var predicate = Expression.Lambda<Func<T, bool>>(
expression,
memberAccessor.Parameters);
return predicate;
}
Run Code Online (Sandbox Code Playgroud)
这会给你一个计算结果的表达式:
Expression<Func<BDEntity, bool>> expression = _ =>
string.IsNullOrEmpty(term)
|| _.DBEntityField.StartsWith(term)
Run Code Online (Sandbox Code Playgroud)
这个表达式有几个优点:
SQLterm是null或时返回所有记录emptyStartsWith确保可以使用适当的索引。该expression可类似地加入到与查询query = query.Where(expression),替换StartsWith与Contains将用于在字符串中任何匹配搜索,但你会放弃任何SQL指数的优化,所以它的禁忌。