如何在表达式树中编写 string.Contains(someText)

Ric*_*d77 3 c# linq expression-trees

这是我学习表达式树的教程

我有超过 35 列要显示,但用户可以选择一次显示 10 列。因此,当用户在搜索框中键入内容时,我只想搜索用户可见的列。

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%')
Run Code Online (Sandbox Code Playgroud)

回到 Linq,这就是我试图完成它的方式:

var result = db.Students
    .Where(GetPredicate(id, listOfColumns))
    .ToList();
Run Code Online (Sandbox Code Playgroud)

这是私有方法:

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;
}
Run Code Online (Sandbox Code Playgroud)

如上所述,它运行良好。但是,我什至编写此方法的原因是能够仅按用户选择的列进行过滤。

我希望能够根据 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);
   }
}
Run Code Online (Sandbox Code Playgroud)

我完全迷失了。我知道我需要访问字符串类的Contains 方法然后我不知道接下来要做什么。想法是得到这样的东西:

Where(d => d.Id == id && (d.FirstName.Contains(searchText) 
        || d.LastName.Contains(searchText) 
        || ...
        || d.State.Contains(searchText)))
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助

das*_*ght 5

你很接近,除了构造调用Contains没有右侧:

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
);
Run Code Online (Sandbox Code Playgroud)

获得调用表达式后,将它们与 组合OrElse以生成 lambda 的主体。您可以使用循环来完成,也可以使用 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);
}
Run Code Online (Sandbox Code Playgroud)