我如何迭代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
答案 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 their
左and
右'属性来查找的表达式输出要比较的属性名称和值..但对于这种简单类型的表达式,它不应该太多工作。
答案 2 :(得分:-1)
你不想走这条路。您将重新实现LINQ to SQL。我可能会建议您使用可选参数:
public DataSet GetProduct(int? maxPrice = null, string type = null)
{
//... snip ...
if (price.HasValue) whereClause += " OR price <= " + maxPrice";
//... snip ...
}