迭代Linq表达式并将其转换为DB参数

时间:2010-12-14 22:33:02

标签: c# linq ado.net

我如何迭代Linq表达式并将其转换为DB参数,以便我可以避免将多个参数作为输入传递给DAL方法

业务层:  在BL我有这样的代码

  database.GetProduct(a => a.ProductType == "tea" || a.Price <= 5);

在DAL中,我使用普通的ADO.Net,并希望将从BL返回的表达式转换为ADO.Net参数

数据访问层:

 public DataSet GetProduct(Expression<Func<Product, bool>> pred)
 {

    step 1:
          Iterate the predicate and create new sqlparameter.
    step 2:
      return database.ExecuteDataset(parameters)    
 }

我如何迭代“pred”&amp;将其转换为SQLParameter

3 个答案:

答案 0 :(得分:1)

您需要研究在表达式上使用访问者模式,以便您可以遍历生成的表达式树,以确定要作为参数投影的成员。 IQToolkit项目有一个很好的ExpressionVisitor基类,你可以发现它有用作访问者模式的基础实现。您可以将其子类化以专门处理VisitMemberAccess以处理您的属性。

答案 1 :(得分:1)

正如Matthew所写,你需要处理表达式树。这可以使用ExpressionVisitor来完成,它允许您为表达式树中的每种类型的节点编写一些代码。但是,如果您只想支持简单表达式(例如示例中的表达式),那么您可以使用NodeType属性来处理它。

结构可能类似于:

static void HandlePrimitive(Expression e) {
  // TODO: Handle primitive cases (>, <, <=, !=, >=, ..)
  Console.WriteLine(e.NodeType);
}

static void Process(Expression e) {
  if (e.NodeType == ExpressionType.OrElse)
  {
    // Process left subexpression (one (in)equality) as primitive
    // and right subexpression recursively (it may be either primitive 
    // or another OrElse node.
    var be = e as BinaryExpression;
    HandlePrimitive(be.Left);
    Process(be.Right);
  }
  else HandlePrimitive(e);
}

Expression<Func<Product,bool>> f = a => a.ProductType == "tea" || a.Price <= 5;
Process(f.Body);

Process方法递归迭代使用“或”运算符组成的所有子表达式(您可以支持“和”类似)。 HandlePrimitive方法会处理可能使用||'s. These are other BinaryExpression values (e.g.等于or LessThanEqual ). You'll need to look at theirand右'属性来查找的表达式输出要比较的属性名称和值..但对于这种简单类型的表达式,它不应该太多工作​​。

答案 2 :(得分:-1)

你不想走这条路。您将重新实现LINQ to SQL。我可能会建议您使用可选参数:

public DataSet GetProduct(int? maxPrice = null, string type = null)
{
    //... snip ...
    if (price.HasValue) whereClause += " OR price <= " + maxPrice";
    //... snip ...
}