假设我有这些简化的EF生成实体......
public class PurchaseOrder
{
public int POID {get;set;}
public int OrderID {get;set;}
public int VendorID {get;set;}
public IEnumerable<Order> Orders {get;set;}
}
public class Order
{
public int OrderID {get;set;}
public decimal Price {get;set;}
public IEnumerable<Item> Items {get;set;}
}
public class Item
{
public int OrderID {get; set;}
public string SKU {get;set;}
public int VendorID {get;set;}
public Order Order {get;set;}
}
业务逻辑:
订单可以包含多个PO,订单上的每个不同供应商都有一个(供应商在商品级别确定)。
如何选择性地包含子实体?
在查询PO时,我想自动为订单和项目添加子项目。
我使用Include()...
完成此任务Context.PurchaseOrders.Include("Orders.Items");
这是工作并撤回相关实体,但是, 我只想包含其VendorID与PurchaseOrder实体的VendorID匹配的Item实体 。
对于传统的SQL,我只是将它包含在JOIN条件中,但EF在内部构建它们。
我可以使用哪种LINQ魔法告诉EF应用条件,而无需在实体之间手动创建JOIN?
答案 0 :(得分:3)
您无法有选择地撤回符合特定条件的某些子实体。您可以做的最好的事情是亲自手动过滤相关订单。
public class PurchaseOrder
{
public int POID {get;set;}
public int OrderID {get;set;}
public int VendorID {get;set;}
public IEnumerable<Order> Orders {get;set;}
public IEnumerable<Order> MatchingOrders {
get {
return this.Orders.Where(o => o.VendorId == this.VendorId);
}
}
}
答案 1 :(得分:3)
你做不到。 EF不允许急切加载的条件。您必须使用多个查询,例如:
var pos = from p in context.PurchaseOrders.Include("Order")
where ...
select p;
var items = from i in context.Items
join o in context.Orders on new { i.OrderId, i.VendorId}
equals new { o.OrderId, o.PurchaseOrder.VendorId }
where // same condition for PurchaseOrders
select i;
或者您可以在单个查询中使用投影:
var data = from o in context.Orders
where ...
select new
{
Order = o,
PurchaseOrder = o.PurchaseOrder,
Items = o.Items.Where(i => i.VendorId == o.PurchaseOrder.VendorId)
};
答案 2 :(得分:1)
您可以在此处使用IQueryable-Extensions:
https://github.com/thiscode/DynamicSelectExtensions
Extension以动态方式构建匿名类型。这将用于@ Ladislav-Mrnka所描述的投影。
然后你可以这样做:
var query = query.SelectIncluding( new List<Expression<Func<T,object>>>>(){
//Example how to retrieve only the newest history entry
x => x.HistoryEntries.OrderByDescending(x => x.Timestamp).Take(1),
//Example how to order related entities
x => x.OtherEntities.OrderBy(y => y.Something).ThenBy(y => y.SomeOtherThing),
//Example how to retrieve entities one level deeper
x => x.CollectionWithRelations.Select(x => x.EntityCollectionOnSecondLevel),
//Of course you can order or subquery the deeper level
//Here you should use SelectMany, to flatten the query
x => x.CollectionWithRelations.SelectMany(x => x.EntityCollectionOnSecondLevel.OrderBy(y => y.Something).ThenBy(y => y.SomeOtherThing)),
});