【问题标题】:LINQ where condition with dynamic columnLINQ where条件与动态列
【发布时间】:2019-03-28 18:04:26
【问题描述】:

我有这个代码

// IQueryable<General> query

if (columnName == "Column1") 
{
  query = query.Where(x => x.Column1 == searchValue);
}
else if (columnName == "Column2") 
{
  query = query.Where(x => x.Column2 == searchValue);
}
else if (columnName == "Column3") 
{
  query = query.Where(x => x.Column3 == searchValue);
}
else if (columnName == "Column4") 
{
  query = query.Where(x => x.Column4 == searchValue);
}
// next zilions columns to come
// ...

我的问题是。我如何通过 x.Column 作为“.Where”条件中的参数?

【问题讨论】:

  • "next zilions columns to come" 你应该重构你的数据模型。为什么你有这么多类似的列?请改用另一张桌子。那么你的查询也变得非常简单和高效。
  • 你不能..不是以任何简单的方式..但你不能直接通过 (searchValue, columnName) 传递Expression&lt;Func&lt;Typeofx, bool&gt;&gt; filterExpression 吗?用作query.Where(filterExpression) columnName、searchValue 是从哪里来的?为什么以这种方式指定它们
  • @TimSchmelter 它的报告表列.. 每列包含不同的数据。目的是让用户单独过滤每一列。
  • @bommelding 实际上我的答案应该适用于 Linq-To-Sql(因为我正在使用表达式)
  • @AleksAndreev - 布丁的证据在于吃...它真的有效吗?

标签: c# entity-framework linq dynamic linq-to-sql


【解决方案1】:

您可以手动创建谓词。使用这个方法:

public static Expression<Func<General, bool>> CreatePredicate(string columnName, object searchValue)
{
    var xType = typeof(General);
    var x = Expression.Parameter(xType, "x");
    var column = xType.GetProperties().FirstOrDefault(p => p.Name == columnName);

    var body = column == null
        ? (Expression) Expression.Constant(true)
        : Expression.Equal(
            Expression.PropertyOrField(x, columnName),
            Expression.Constant(searchValue));

    return Expression.Lambda<Func<General, bool>>(body, x);
}

现在你可以应用你的谓词了:

IQueryable<General> query = //
var predicate = CreatePredicate(columnName , searchValue);
query = query.Where(predicate);

【讨论】:

  • 不完全确定,但您不会错过Expression.Convert 的常量值吗?我想我必须在前一段时间使用它,否则它会抛出异常。
【解决方案2】:

您可以使用reflection 和扩展方法。举个粗略的例子:

public class Foo
{
  public int Column1 { get; set; }
  public int Column2 { get; set; }
  ...
}

public static class FooExtensions
{
  // I would use the actual type here instead of object if you know the type.
  public static object GetProperyValue(this Foo foo, string columnName)
  {
    var propertyInfo = foo.GetType().GetProperty(columnName);
    var value = propertyInfo.GetValue(foo);
    // as well as cast value to the type
    return value;
  }
}

...

query = query.Where(x => x.GetProperyValue(columnName) == searchValue);
...

附带说明,这不是一个精心设计的查询,因为每次向模型添加列时,都需要更新 if-else。它违反了SOLID中的O。

【讨论】:

  • 这在 Linq to Entities 中不起作用(我认为我们可以假设最常用的 IQueryProvider),它不能将方法转换为有效的 SQL
  • @AlexanderDerck,是的,你是对的。这是一个有效的观点。没有看到第一条评论。
【解决方案3】:

您可以使用反射通过名称检索属性

x.GetType().GetProperty(propertyName,BindingFlags).SetValue(x,value)
// propertyName = "Column1" for example
// BindingFlags are most likely Instance, Public and Property (IIRC)

或将 PropertyInfo 作为参数直接传递到方法中。您的选择取决于您希望向方法的使用者公开的抽象级别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 2013-12-30
    相关资源
    最近更新 更多