2011-10-28 67 views
0

我有一个相当复杂的查询,我需要写。如果可能,我希望使用Linq to Sql来完成它。该数据库是这样的:用动态LINQ查询子表到sql?

客户(第一,最后,ID,性别)
订单(日期,数量,重量,ITEMNAME,价格)
地址(城市,州,邮编)

该查询将让用户通过任何这些字段进行搜索,并且在数字字段的情况下,按照他们的期望搜索<,=,或>。

像这样的事情将是我需要实现简单的查询:

查询1: 选择客户,其中第一名称=“约翰”,并至少有一个订单与(重量> 40或数量> 10或价格> 5)和邮政编码= 12345

问题2: 选择客户其中第一名称=“约翰”和具有至少一个以便与重量< 20和ITEMNAME =“插件”和数量= 10)和zipcode = 12345.

我可以得到搜索的基本部分f或客户,但我坚持搜索订单表,用户可以用OR方式指定<> =。

query = Context.Customers.AsQueryable(); 
if (searchingFirstName) query = query.Where(cust => cust.First == firstName); 
if (searchingLastName) query = query.Where(cust => cust.Last == lastName); 
if (searchingZip) query = query.Where(cust => cust.Address.Zip == zip); 

// using dynamic Linq 
if (searchingGender) query = query.Where("Gender == @0", gender); 

// how do I search the Orders? The dynamic linq functions appear 
// to only work on the top level table 

回答

1

你可以从LinqKit使用PredicateBuilder。它增加了一些新的扩展方法,lambda表达式断言:

var predicate = PredicateBuilder.True<Customer>(); 

if (searchingFirstName) 
{ 
    predicate = predicate.And(cust => cust.First == firstName); 
} 

if (searchingOrders) 
{ 
    // Some code to unify the .And() and .Or() cases 
    Expression<Func<Order, bool>> subpredicate; 
    Func<Expression<Func<Order, bool>>, Expression<Func<Order, bool>>, Expression<Func<Order, bool>>> joiner; 
    if (orderMethodAny) 
    { 
     subpredicate = PredicateBuilder.True<Order>(); 
     joiner = PredicateBuilder.And; 
    } 
    else 
    { 
     subpredicate = PredicateBuilder.False<Order>(); 
     joiner = PredicateBuilder.Or; 
    } 

    if (searchingOrderDate) 
    { 
     // ... 
    } 

    if (searchingOrderWeight) 
    { 
     switch (orderOp) 
     { 
      case Op.Less: 
       subpredicate = joiner(subpredicate, ord => ord.Weight < orderWeight); 
       break; 
      case Op.LessEqual: 
       subpredicate = joiner(subpredicate, ord => ord.Weight <= orderWeight); 
       break; 
      case Op.Equal: 
       subpredicate = joiner(subpredicate, ord => ord.Weight == orderWeight); 
       break; 
      case Op.GreaterEqual: 
       subpredicate = joiner(subpredicate, ord => ord.Weight >= orderWeight); 
       break; 
      case Op.Greater: 
       subpredicate = joiner(subpredicate, ord => ord.Weight > orderWeight); 
       break; 
      case Op.NotEqual: 
       subpredicate = joiner(subpredicate, ord => ord.Weight != orderWeight); 
       break; 
     } 
    } 

    if (searchingOrderQuantity) 
    { 
     // ... 
    } 

    if (searchingOrderItemName) 
    { 
     // ... 
    } 

    if (searchingOrderPrice) 
    { 
     // ... 
    } 

    predicate = predicate.And(cust => cust.Orders.Any(subpredicate)); 
} 

if (searchingZipCode) 
{ 
    predicate = predicate.And(cust => cust.ZipCode == zipCode); 
} 

var query = Context.Customers.Where(predicate); 

您可能需要将它们作为参数,或.AsExpandable()上可查询前呼吁谓词.Expand(),如果您使用的是实体框架。

+0

非常感谢。很好的答案。我不得不在subpredicate上调用.Compile()。 (cust => cust.Orders.Any(subpredicate.Compile());不幸的是,我意识到现在我的问题并不完全正确。 – David

+0

.Compile()会将表达式转换为委托。系统在客户端而不是数据库上执行过滤 –

+0

在重写它以使用实际查询之后,我不再需要任何Expand(),AsExpandable()或Compile(),但它的工作非常精美。 – David