2011-11-30 80 views
6

假设我有这些简化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;} 
} 

业务逻辑:

一个订单可以有多个POS,一个用于订单上的每个不同供应商(供应商均在项目级别确定)。

如何选择性地包含子实体?

当查询PO时,我想自动包含Order和Item的子实体。

我做到这一点,利用包括()...

Context.PurchaseOrders.Include("Orders.Items"); 

但这是工作,拉回到相关的实体,但是,我只想包括项目实体的厂商ID的的厂商ID匹配PurchaseOrder实体

对于传统的SQL,我只是将它包含在JOIN条件中,但EF在内部构建它们。

我可以使用什么LINQ魔术来告诉EF应用条件,而无需手动创建实体之间的JOIN?

回答

2

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

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); 
     } 
    } 
} 
+0

我希望看到这是在未来增强功能。 – ctorx

+0

@Matthew - 他们对框架 –

+0

超过五年是一个很好的补充,但仍然没有什么......令人惊讶的是,对于EF可能具有的最有用功能之一来说这不是一件坏事...... -.-“ – Shockwaver

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

你可以在这里使用的IQueryable的扩展:

https://github.com/thiscode/DynamicSelectExtensions

的扩展动态构建一个匿名类型。这将用于@ 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)), 

});