2011-08-11 85 views
5

我只是用Entity Framework弄溼了自己的腳,但是我對DBSet對象的一些行爲感到有些莫名其妙。當我調用Find()方法時,它似乎意識到我最近添加的(但尚未保存的)項目的集合,但是當我嘗試查詢DBSet時,它似乎只包含一直存在的項目。有沒有簡單的方法來解決這個問題?我包括一些代碼,我已經做了嘗試解決這個問題,但是當它開始通過從我的「添加」變更集的項目進行迭代,我得到這個錯誤:有沒有辦法在DBSet的查詢中包含本地緩存的項目?

"Unable to create a constant value of type EntityType. Only primitive types ('such as Int32, String, and Guid') are supported in this context."

internal DbContext Context { get; set; } 
protected DbSet<T> DBSet { get; set; } 

public virtual IEnumerable<T> Get(
    Expression<Func<T, bool>> filter = null, 
    Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, 
    bool ignoreCachedChanges = false) 
{ 
    IQueryable<T> oReturn = DBSet; 

    // This block is intended to adjust the queryable source to account for changes 
    if (!ignoreCachedChanges) 
    { 
     oReturn = oReturn.Except(Context.ChangeTracker.Entries<T>().Where(x => x.State == System.Data.EntityState.Deleted).Select(x => x.Entity)); 
     oReturn = oReturn.Union(Context.ChangeTracker.Entries<T>().Where(x => x.State == System.Data.EntityState.Added).Select(x => x.Entity)); 
    } 
    if (filter != null) 
     oReturn = oReturn.Where(filter); 

    if (orderBy != null) 
     return orderBy(oReturn).ToList(); 
    else 
     return oReturn.ToList(); 
} 

// NOTE: Get By ID uses Find which considers the queued-but-not-yet-applied changes 
public virtual T GetByID(object id) 
{ 
    return DBSet.Find(id); 
} 

(在上下文有幫助的情況下,我這樣做是因爲我想設置一個單元測試,在其中填充我的(本地)上下文,以滿足特定測試環境的項目......我很快就不需要應用這些變化,因爲他們真的只適用於特定的測試,但我可以,如果需要的話...在這樣做,我很驚訝地發現,存儲庫不包括其查詢結果中的變化項目 - 除非我在做FindByID - 所以我也希望我能解決這種明顯的不一致性,或者g或者更好的理解爲什麼這是不可行的或者不是一個好主意? :))

回答

2

異常說明:您不能發送實體類型(您的泛型類型T)到服務器的列表以執行SQL中的ExceptUnion,這些「常量」對象的這些集合。基本上你必須在LINQ to Objects的內存中應用ExceptUnion,這意味着:在之後的已經實現了來自服務器的過濾結果(因此在.ToList()之後的某處)。您必須再次將過濾器應用於上下文中處於Added狀態的對象列表。

+0

謝謝!這讓我更好地理解發生了什麼。另外,如果您碰巧讀到:這是我的存儲庫查詢方法的明智方法嗎?我會傾向於認爲,因爲這個「離線」集合具有排隊的插入/刪除,它應該考慮那些(如DBSet.Find()似乎這樣做),但是有沒有理由不這樣做,我可能會忽略? – Steven

+1

@Steven:'Find'非常特別。它只查詢主鍵。這可以在內存(第1步)和SQL中使用(第2步,如果第1步中沒有發現任何內容)。對於其他查詢,您必須記住,EF必須使用LINQ to Entities執行查詢,然後使用LINQ to Objects查詢來構建聯合。有些查詢甚至不能在LINQ to Objects(例如使用'EntityFunctions')時完成。或者相同的查詢可以有不同的行爲(例如,字符串搜索的區分大小寫)。僅使用一個查詢規範執行兩個查詢並非易事,也不可能。 – Slauma

+1

(續)可能是它沒有按照您的意願實施的原因。這些也是您的通用泛型實現在ChangeTracker中構建DB查詢對象和對象的聯合的原因:您的'filter'應用於LTO或LTE時可能會給出不同的結果,或者它甚至不適用於LTO。我懷疑一個乾淨的通用實現是可能的。我會盡量避免你需要查詢'ChangeTracker'。如果你真的需要,不要嘗試一種通用的方法,只能在你的特定情況下進行,並且必須在特定的查詢中進行。 – Slauma

相關問題