【问题标题】:Querying child tables with dynamic linq to sql?使用动态 linq to sql 查询子表?
【发布时间】:2011-12-17 12:39:49
【问题描述】:

我需要编写一个相当复杂的查询。如果可能的话,我希望使用 Linq to Sql 来做到这一点。数据库是这样的:

客户(名字、姓氏、ID、性别)
订单(日期、数量、重量、商品名称、价格)
地址(城市、州、邮编)

查询是让用户通过这些字段中的任何一个进行搜索,如果是数字字段,则可以根据需要搜索 。

这样的事情是我需要实现的示例查询:

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

查询 2: 选择名字 = 'John' 并且至少有一个重量

我可以获得搜索客户的基本部分,但我一直在搜索 Order 表,用户可以在其中以 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

【问题讨论】:

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


    【解决方案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);
    

    在将谓词作为参数传递之前,您可能需要在谓词上调用 .Expand(),或者在可查询对象上调用 .AsExpandable(),如果您使用的是实体框架。

    【讨论】:

    • 非常感谢。很好的答案。我不得不在子谓词上调用 .Compile() 。 predicate = predicate.And(cust => cust.Orders.Any(subpredicate.Compile()); 不幸的是我现在意识到我的问题并不完全正确。
    • .Compile() 会将表达式转换为委托。这将使系统在客户端而不是数据库上进行过滤。
    • 重写它以使用真正的查询后,我不再需要任何 Expand()、AsExpandable() 或 Compile()。但它工作得很好。
    猜你喜欢
    • 2012-12-21
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    相关资源
    最近更新 更多