2017-05-10 24 views
1

我有一個類的方法來檢索數據從SQLite數據庫使用EF6。EF6加載指定的子實體每個查詢

上下文是在構造函數被注入和那裏爲相同上下文被多次使用爲同一類的實例。我正在使用實體框架6的Include擴展方法在查詢中包含子實體。要包含的項目在參數中指定,因此可以根據調用者的要求進行更改。

這裏是類的一個示例:

public class AccountManager 
{ 
    private SQLiteContext context; 

    // Injected Context 
    public AccountManager(SQLiteContext Context) 
    { 
     context = Context; 
    } 

    public Account GetAccountById(int AccountId, string ToInclude) 
    { 
     return context.Account 
         .Include(ToInclude) 
         .Single(a => a.AccountId == AccountId) 
    } 
} 

的問題是,如果我有一個孩子實體在我的第一個查詢(查詢),它工作正常,但如果我有一個不同孩子實體在後續查詢中(使用相同的上下文)查詢A的子實體也包括在內。例如:

AccountManager am = new AccountManager(MyContext); 

// Run first query 
var a1 = am.GetAccountById(1, "Payments"); 

// Run second query 
// The result of this query also includes child entity "Payments" 
// because it was added to the context in the previous query 
var a2 = am.GetAccountById(1, "Owners"); 

有沒有我可以防止這種情況發生,並且每個查詢的「包含」設定唯一處理的方式?

+1

使用相同的上下文時:僅通過從上下文中分離付款。或者用'AsNoTracking()'獲取數據。 –

+0

這實際上是正確的答案(如果您將其更改爲答案,我會將其標記爲正確的答案) - 應每次爲每項「工作」實例化「AccountManager」類,以便上下文可以相應地進行跟蹤。這個類將最終放在WCF服務後面,這樣問題就會解決(每個請求都會創建一個新的上下文)。但目前它是MVVM(Light)項目的_DataService_部分,所以IOC將該類實例化一次,並被所有其他虛擬機重新使用。感謝您指點我正確的方向。 –

回答

1

當Entity Framework從數據庫中獲取實體時,默認行爲是將實體添加到其更改跟蹤器中。更改跟蹤器不僅跟蹤個別實體的更改,還跟蹤關聯。因此,EF還會填充其變更跟蹤器緩存中實體可找到的任何導航屬性。

因此,當您向擁有者提取賬戶時,無論您是否喜歡,EF仍會找到所有付款並填寫account.Payments

我覺得你的情況,你能做的最好是沒有跟蹤來獲取實體:

return context.Account.AsNoTracking() 
       .Include(ToInclude) 
       .Single(a => a.AccountId == AccountId) 

現在,EF將填充PaymentsOwners,而不是這些實體添加到它的高速緩存。在N層應用程序中,在大多數情況下,最好使用AsNoTracking,因爲更改應用於上下文中的實體並且AsNoTracking性能更好,因爲更新更改跟蹤器和關係修復是昂貴的過程。

或者,您可以將實體標記爲EntityState.Detached,但我不會走這條路。

最好的方法是爲每個業務事務使用一個新的上下文,所以這是很好的,你正在向這個方向發展。

0

重要提示:如果您有一對多的關係,我不會建議您這樣做。這個很貴。我寧願創建兩個不同的查詢。

但是,如果你想這樣做,我認爲一個更好的選擇可以做一個動態查詢,是非常有用的。類似的東西:

public Account GetAccountById(int AccountId, bool includePayments = false, bool includeOwners) 
    { 
     var query = context.Account; 

     if(includePayments) 
     { 
     query = query.Include(c => c.Payments).AsQueryable() 
     } 

     if(includeOwners) 
     { 
     query = query.Include(c => c.Owners).AsQueryable() 
     } 

     return query.Single(a => a.AccountId == AccountId) 
} 
+0

仔細閱讀。這不是問題。 –

0

它實際上是一個優化的實體框架爲你做這個。

實體框架在執行查詢時構建數據樹。

值得問問自己,爲什麼你想排除這些信息。

相關問題