使用Linq动态查询数据集

时间:2019-02-06 21:07:35

标签: c# linq dynamic-linq

我有一个要动态查询的数据集。如果我明确定义字段名称,则此代码可以正常工作,但是我不想这样做。我想使用变量作为字段名称来动态查询数据。我应该如何处理?

这有效:

var dataField = "DemandStatusName";
var searchParam = form.GetValues("columns[" + j + "][search][value]").FirstOrDefault();

if(searchParam != "")
{
    dataSet = (from a in dataSet
               where a.DemandStatusName.Contains(searchParam)
               select a);
}

但这不是:

var dataField = "DemandStatusName";
var searchParam = form.GetValues("columns[" + j + "][search][value]").FirstOrDefault();

if(searchParam != "")
{
    dataSet = (from a in dataSet
               where dataField.Contains(searchParam)
               select a);
}

2 个答案:

答案 0 :(得分:1)

  

我应该如何处理?

LINQ的主要优点之一是您可以安全地输入类型。通过动态查询它,您固有地失去了这一好处。尽管并不是真正的“动态”,但您可以通过编写扩展方法来保留此优势,该方法包括要查询的特定字段:

public static IQueryable<MyTable> WhereContains(this IQueryable<MyTable> source, string field, string value)
{
  switch (field)
  {
    case nameof(MyTable.SomeField):
      return source.Where(a => a.SomeField.Contains(value));
    case nameof(MyTable.SomeOtherField):
      return source.Where(a => a.SomeOtherField.Contains(value));
    // ... etc
    default:
      throw new ArgumentOutOfRangeException($"Unexpected field {field}");
  }
}

这样,您的代码可以调用以下内容:

var dataField = "DemandStatusName";
var searchParam = form.GetValues("columns[" + j + "][search][value]").FirstOrDefault();

dataset.WhereContains(dataField, searchParam).OrderBy(a => a.Whatever)

也就是说,要从字面上回答您的问题,从技术上讲,您可以动态地构建LINQ表达式。可能看起来像这样,但是请注意性能会很差,意外的值可能会破坏它和/或打开一些安全漏洞,尤其是如果这些漏洞来自用户输入:

var table = Expression.Parameter(typeof(MyTable));
var property = Expression.PropertyOrField(table, dataField);
var param = Expression.Constant(searchParam);
var contains = Expression.Call(property, "Contains", Type.EmptyTypes, searchParam);
var expression = Expression.Lambda<Func<MyTable,bool>>(contains, table);

var result = dataset.Where(expression);

答案 1 :(得分:0)

是否需要使用LINQ?动态SQL(带有参数)会容易得多。

var dataField = "DemandStatusName";
var searchParam = form.GetValues("columns[" + j + "][search][value]").FirstOrDefault();
var sql = string.Format("select * from tableName where {0} = @param", dataField);

if(searchParam != "")
{
    dataSet = context.Database.SqlQuery<YourEntity>(sql,
                  new SqlParameter("param", searchParam));
}