简单的答案是,您可以只在查询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();
动态表达
如果您需要在运行时构建像 _ => _.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;
}
以下断言将通过:
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();
通过将谓词包含在 where 子句中,实体框架可以使用谓词。
var predicate = PredicateExtensions.BuildEqualPredicate<MyDbEntity>(
_ => _.DatabaseField,
"TEST");
var results = context.DbEntity.Where(predicate).ToList();
另外
您可以使用成员表达式做更多事情,例如使用StartsWith 和Contains 创建更复杂的谓词。
Expression<Func<T, string>> memberAccessor = _ => _.DBEntityField;
您可以像这样动态创建谓词,在本例中,它创建一个谓词来检查字符串 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;
}
这将为您提供一个计算结果如下的表达式:
Expression<Func<BDEntity, bool>> expression = _ =>
string.IsNullOrEmpty(term)
|| _.DBEntityField.StartsWith(term)
这个表达式有几个优点:
- 可以转换成合适的
SQL
- 当
term 为null 或empty 时返回所有记录
-
StartsWith 确保可以使用适当的索引。
expression 可以类似地使用 query = query.Where(expression) 添加到查询中,将 StartsWith 替换为 Contains 将搜索字符串中的任何匹配项,但您将放弃任何 SQL 索引优化,所以是禁忌的。