用动态linq查询子表到sql?

时间:2011-10-28 18:55:23

标签: c# .net linq-to-sql

我需要编写一个相当复杂的查询。我希望尽可能使用Linq to Sql。数据库是这样的:

客户(第一,最后,身份证,性别)
订单(日期,数量,重量,物品名称,价格)
地址(城市,州,邮编)

查询将允许用户通过任何这些字段进行搜索,并且在数字字段的情况下,搜索<,=或>他们想要的。

这样的东西就是我需要实现的示例查询:

查询1: 选择名字='John'并且至少有一个订单的客户(重量> 40或数量> 10或价格> 5)和zipcode = 12345。

查询2: 选择名字='John'的客户,并且至少有一个订单的权重< 20和ItemName ='widget'和Quantity = 10)和zipcode = 12345。

我可以获得搜索客户的基本部分,但我仍然坚持搜索订单表,用户可以在其中以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 个答案:

答案 0 :(得分:1)

您可以使用LinqKit中的PredicateBuilder。它添加了一些新的扩展方法来预测lambdas:

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);

如果您使用实体框架,则可能需要在谓词上调用.Expand(),然后在可查询项上调用.AsExpandable()