使用动态链接查询子表
本文关键字:查询 链接 动态 | 更新日期: 2023-09-27 18:12:54
我需要编写一个相当复杂的查询。如果可能的话,我希望使用Linq到Sql。数据库是这样的:
客户(First, Last, ID, Gender)
订单(日期、数量、重量、ItemName、价格)
地址(城市,州,邮政编码)
查询将允许用户搜索这些字段中的任何一个,对于数字字段,可以根据需要搜索<, =或>。
像这样的东西将是我需要实现的示例查询:
查询1:选择名字= 'John'且至少有一个订单(重量> 40或数量> 10或价格> 5)且邮政编码= 12345的客户。
查询2:选择名字= 'John'并且至少有一个Weight <订单的客户;20和ItemName = 'widget'和Quantity = 10)和zipcode = 12345。
我可以获得搜索客户的基本部分,但我被困在搜索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
您可以使用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()
,如果您正在使用实体框架。