entity framework – 包含导航属性的选择条件

假设我有这些简化的EF生成实体……

public class PurchaseOrder { public int POID {get;set;} public int OrderID {get;set;} public int VendorID {get;set;} public IEnumerable Orders {get;set;} } public class Order { public int OrderID {get;set;} public decimal Price {get;set;} public IEnumerable 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?

您无法有选择地撤回符合特定条件的某些子实体。 您可以做的最好的事情是自己手动过滤相关订单。

 public class PurchaseOrder { public int POID {get;set;} public int OrderID {get;set;} public int VendorID {get;set;} public IEnumerable Orders {get;set;} public IEnumerable MatchingOrders { get { return this.Orders.Where(o => o.VendorId == this.VendorId); } } } 

你不能。 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) }; 

您可以在此处使用IQueryable-Extensions:

https://github.com/thiscode/DynamicSelectExtensions

Extension以动态方式构建匿名类型。 这将用于@ Ladislav-Mrnka描述的投影。

然后你可以这样做:

 var query = query.SelectIncluding( new List>>>(){ //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)), });