gpt4 book ai didi

c# - 创建要应用于 IQueryable 的动态搜索的最简单方法

转载 作者:太空宇宙 更新时间:2023-11-03 13:45:30 26 4
gpt4 key购买 nike

考虑具有以下列和相应实体的单个表(称为 Car)的情况

string Make
string Model
string Owner

现在我想创建一个搜索,用户可以在其中选择(通过使用复选框)搜索应该定位到哪些属性。如果选择了多个,那么只要在其中至少一个中找到搜索字符串就足够了。

此外,如果给出了多个搜索字符串(用空格分隔),则搜索应该仅在找到每个单词时才匹配(例如,给定搜索字符串“ter mist”,车主为“mister”的汽车将匹配)。

经过一些研究,我想我应该创建一个 Expression<Func<Car, bool>> 的列表对于每个选定的属性,为搜索字符串中的每个单词添加一个,然后所有这些一起创建一个 Expression<Func<Car, bool>> .一旦我为所有选定的属性获得了这些,我就会将它们组合在一起,以创建最终的过滤器。然而,这正是我苦苦挣扎的地方。

最后,我得到的最远的是 NotSupportedException 说 The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.

以下是我用于合并的辅助函数(来自 http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/60a1f4c0-d4d9-4143-91aa-79d29dde7a7c/ ):

public static Expression<Func<T, bool>> Or<T>(params Expression<Func<T, bool>>[] predicates)
{
if (predicates.Length == 1)
return predicates[0];

Expression<Func<T, bool>> result = predicates[0];
for (int i = 1; i < predicates.Length; i++)
{
result = OrTwo(result, predicates[i]);
}

return result;
}
private static Expression<Func<T, bool>> OrTwo<T>(Expression<Func<T, Boolean>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return (Expression.Lambda<Func<T, Boolean>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters));
}

这一切也变得令人惊讶地令人困惑,所以我开始认为一定有更简单的方法来解决这个问题。那么,解决这个问题最简单的方法是什么?


解决方案

在尝试了几种方法(LINQKit、Albahari's PredicateBuilder、自己摆弄表达式树)之后,我终于得到了 here。 .这个通用版本的 PredicateBuilder 无需任何其他外部依赖项即可工作,并且与 EF 完全兼容。它使解决问题变得非常简单。

最佳答案

几周前我决定自己解决这个问题。

查看我的博文:

http://jnye.co/Posts/5/generic-repository-search-function-with-expression-trees

链接更新:我现在创建了一个新帖子,将搜索功能作为扩展方法添加到 IQueryable:

http://jnye.co/Posts/6/c%23-generic-search-extension-method-for-iqueryable

您应该能够根据自己的需要调整它。

已更新

下面是我创建的搜索功能的摘录。

/// <summary>  
/// Performs a search on the supplied string property
/// </summary>
/// <param name="stringProperty">Property to search upon</param>
/// <param name="searchTerm">Search term</param>
public virtual IQueryable<T> Search(Expression<Func<T, string>> stringProperty, string searchTerm)
{
var source = this.RetrieveAll();

if (String.IsNullOrEmpty(searchTerm))
{
return source;
}

//Create expression to represent T.[property] != null
var isNotNullExpression = Expression.NotEqual(stringProperty.Body, Expression.Constant(null));

//Create expression to represent T.[property].Contains(searchTerm)
var searchTermExpression = Expression.Constant(searchTerm);
var checkContainsExpression = Expression.Call(stringProperty.Body, typeof(string).GetMethod("Contains"), searchTermExpression);

//Join not null and contains expressions
var notNullAndContainsExpression = Expression.AndAlso(isNotNullExpression, checkContainsExpression);

//Build final expression
var methodCallExpression = Expression.Call(typeof (Queryable),
"Where",
new Type[] {source.ElementType},
source.Expression,
Expression.Lambda<Func<Club, bool>>(notNullAndContainsExpression, stringProperty.Parameters));

return source.Provider.CreateQuery<T>(methodCallExpression);
}

您应该能够重构生成 methodCallExpression 的代码以创建多个搜索表达式,然后您可以使用 Expression.OrElse() 组合这些表达式。

关于c# - 创建要应用于 IQueryable 的动态搜索的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501151/

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