gpt4 book ai didi

linq - 如何在 Entity Framework 中使用 LINQ 查询的客户谓词,扩展方法 "Search by Words"

转载 作者:行者123 更新时间:2023-12-05 09:20:18 28 4
gpt4 key购买 nike

我想使用谓词构建自定义 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)));
}

...我正在使用通用方法 Search(predicate, searchExpression) 扩展 DbContext,它与静态方法具有相同的效果(见上文)

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)));
}
}

但是,我收到以下错误:

Error 6 Instance argument: cannot convert from 'System.Linq.Expressions.Expression>' to '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();

动态表达

如果您需要在运行时构建类似 _ => _.MyFieldValue == "TEST" 的表达式,那就有点棘手了。

给定一个谓词 _ => _.DatabaseField 和一个字符串值 "TEST",创建一个适合于 Entity Framework 来创建一个测试谓词的 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();

Entity Framework 可以通过将谓词包含在 where 子句中来使用谓词。

var predicate = PredicateExtensions.BuildEqualPredicate<MyDbEntity>(
_ => _.DatabaseField,
"TEST");
var results = context.DbEntity.Where(predicate).ToList();

另外

您可以对成员表达式做更多的事情,例如使用 StartsWithContains 来创建更复杂的谓词。

Expression<Func<T, string>> memberAccessor = _ => _.DBEntityField;

您可以像这样动态地创建一个谓词,在此示例中,它创建一个谓词来检查字符串 StartsWith 是否为特定值,或是否为 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
  • termnullempty时返回所有记录
  • StartsWith 确保可以使用适当的索引

expression 可以类似地添加到带有 query = query.Where(expression) 的查询中,将 StartsWith 替换为 Contains 将搜索字符串中的任何匹配项,但您将放弃任何 SQL 索引优化,因此这是禁忌的。

关于linq - 如何在 Entity Framework 中使用 LINQ 查询的客户谓词,扩展方法 "Search by Words",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38205592/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com