如何在表达式树中写入string.Contains(someText) [英] How to write string.Contains(someText) in expression Tree
问题描述
这是本教程我正在学习表达式树.
This is the tutorial I'm following to learn Expression Tree.
我要显示超过35列,但用户可以选择一次显示10列.因此,一个用户在搜索框中键入内容,我只想搜索用户可见的列.
I've more than 35 columns to display, but the user can chose to display 10 columns at once. So one the user type something in the search box, I want to search only the columns that are visible to the user.
SELECT FirstName, LastName, Address, ..., State
FROM Students
WHERE Id == @Id col1 AND (
FirstName LIKE '%@searchText%' OR
LastName LIKE '%@searchText%' OR
Address LIKE '%@searchText%' OR
...
State LIKE '%@searchText%')
回到Linq,这就是我要完成的方式:
Back to Linq, this is how I'm trying to accomplish it:
var result = db.Students
.Where(GetPredicate(id, listOfColumns))
.ToList();
这是私有方法:
private Expression<Func<Student, bool>> GetPredicate(int id, List<string> listOfColumns)
{
ParameterExpression pe = Expression.Parameter(typeof(Student), "s");
Expression left0 = Expression.Property(pe, "Id");
Expression right0 = Expression.Constant(id);
Expression e0 = Expression.Equal(left0, right0);
//Here ... omitted code because it's not working...
//
var expr = Expression.Lambda<Func<Student, bool>>(e0, new ParameterExpression[] { pe });
return expr;
}
如上所述,它工作正常.但是,我什至写这种方法的原因是只能根据用户选择的列进行过滤.
As it is above, it's working just fine. However, the reason I even wrote this method was to be able to filter only by the user-selected columns.
我希望能够根据用户界面中可见的列进行撰写.
I want to be able to compose based on the column that are visible in the UI.
if(!string.IsNullOrEmpty(searchText))
{
foreach (string columnName in columnList)
{
Expression col = Expression.Property(pe, columnName);
Expression left = Expression.Call(pe, typeof(string).GetMethod("Contains"));
Expression right = Expression.Constant(searchText);
Expression e = Expression.IsTrue(left, right);
}
}
我完全迷路了.我知道我需要访问字符串类的Contains方法,然后不知道接下来要做什么.想法是得到这样的东西:
I'm completely lost. I know that I need to access the Contains method of the string class then I don't know what next. The Idea is to get something like this:
Where(d => d.Id == id && (d.FirstName.Contains(searchText)
|| d.LastName.Contains(searchText)
|| ...
|| d.State.Contains(searchText)))
感谢您的帮助
推荐答案
您非常亲密,只是构造Contains
的调用没有右侧:
You are pretty close, except constructing the call of Contains
does not have a right side:
Expression col = Expression.Property(pe, columnName);
Expression contains = Expression.Call(
pe
, typeof(string).GetMethod("Contains") // Make a static field out of this
, Expression.Constant(searchText) // Prepare a shared object before the loop
);
一旦有了调用表达式,就将它们与OrElse
结合起来以生成lambda的主体.您可以使用循环来实现,也可以使用LINQ:
Once you have your call expressions, combine them with OrElse
to produce the body of your lambda. You can do it with loops, or you can use LINQ:
private static readonly MethodInfo Contains = typeof(string).GetMethod(nameof(string.Contains));
public static Expression<Func<Student,bool>> SearchPredicate(IEnumerable<string> properties, string searchText) {
var param = Expression.Parameter(typeof(Student));
var search = Expression.Constant(searchText);
var components = properties
.Select(propName => Expression.Call(Expression.Property(param, propName), Contains, search))
.Cast<Expression>()
.ToList();
// This is the part that you were missing
var body = components
.Skip(1)
.Aggregate(components[0], Expression.OrElse);
return Expression.Lambda<Func<Student, bool>>(body, param);
}
这篇关于如何在表达式树中写入string.Contains(someText)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!