2011-11-30 81 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)), 

});