2013-10-15 33 views
10

我有N×N的表,試想:LINQ到實體包括+凡採用方法

用戶(ID,...)< - UserAddresses(ID,用戶id,addressId,啓用,...) - >地址(ID ,...)

UserAddresses包含用戶和地址的FK。 據我所知,實體框架用戶創建的實體包含一個到UserAddresses的集合。該地址包含UserAddresses的集合,並且特定的UserAddress包含一個到用戶和一個地址的回車。

現在我想通過linq進行下一個查詢。 對於特定的用戶標識,只獲取啓用標誌設置爲true的userAddresses。 對於特定的用戶標識,userAddresses可以包含多個條目,但只有一個爲此特定用戶設置。

我能做的查詢是:

context.User.Include(x => x.UserAddresses) 
      .Include(x => x.UserAddresses.Select(y => y.Address)) 
      .Single(x => x.id == USER_ID) 

但我真正想要的是不加載所有UserAddresses爲該用戶設置好的爲TRUE ......只有一個包含啓用!

有人可以幫我做這個查詢嗎?

+0

你使用了什麼樣的'Include'?據我所知'System.Data.Objects.ObjectQuery'的Include方法只接收1個字符串參數? –

+0

@KingKing我已經完成了一個擴展方法,將lambda表達式格式化爲字符串,並將其傳遞給「native」ObjectQuery包含方法。 – anotherNeo

+0

如果是這樣,你的問題的答案是'不可能','包括'不是如此強大,你不能在包含之前執行任何'過濾器'。 –

回答

14

EF無法部分加載關聯屬性。請嘗試選擇到一個匿名類型只需要採取什麼:

var result = context.User 
    .Where(u => u.Id == userId) 
    .Select(u => new { 
     Addresses = u.UserAddresses.Select(ua => ua.Address) 
      .Where(a => a.Enabled), 
     User = u // if you need this as well 
    }) 
    .Single(); 

這將不加載result.User.UserAddresses,但result.Addresses將有你想要什麼。

如果您確實想要將所有內容作爲User類的一部分返回,您需要分離result.User,然後更新result.User.UserAddresses以指向result.Addresses。

+0

我需要返回用戶實體相關的所有東西,但不是所有的集合映射..所以我認爲匿名類型是不正確的:/ – anotherNeo

+0

@goncaloRD:不幸的是'where'條件不可能使用'包括'的。這是你最好的選擇。 – Ocelot20

+0

@ChaseMedallion謝謝,這正是我所需要的。查詢完成,EF對象按照我想要的方式映射。 我創建了一個Type來讓我的對象具有代表性,以用於我的業務層。 – anotherNeo

1

另一種替代方案是使用Load(),而不是包括():

var foundUser = context.User.Single(x => x.Id == USER_ID); 

context.Entry(foundUser).Collection(u => 
u.UserAddresses).Query().Where(userAddress => 
userAddress.Enabled).Load(); 

請記住,Load()方法可以通過EF在某些情況下被忽略:

  1. 如果您正在使用EF和Lazy Loading功能,獲取您的對象會帶來所有關聯的集合,這些集合在您的班級中被標記爲「虛擬」。所以這樣做:

    context.User.Single(x => x.id == USER_ID);

    您將獲得與用戶關聯的所有用戶地址,除非您通過從用戶類中的屬性中刪除虛擬關鍵字來關閉集合的延遲加載。

  2. 如果您在程序中添加/刪除UserAddresses集合並調用context.SaveChanges();不用處理你的上下文,下次你加載User對象時,UserAddresses集合將從EF上下文緩存中加載,而不是從DB(你最近的改變)加載。在這種情況下,您需要在從上下文獲取用戶之前,先配置您的上下文並實例化新的上下文。例如,如果您的用戶在UserAddresses集合中包含5個項目,並且您將其中一個項目禁用(item.Enabled = false),然後在不處理您的上下文的情況下調用context.SaveChanges(),則下次獲取User對象時從相同的上下文中,它的集合中已經有5個來自上下文緩存的項目,並且它忽略了您的Load()方法。

PS:

遲緩裝載的功能爲ON,如果施加下面的所有條件:

  1. context.Configuration.LazyLoadingEnabled = TRUE;
  2. context.Configuration.ProxyCreationEnabled = true;
  3. UserAddresses已在User類中定義爲Virtual。