2015-06-10 193 views
3

在此代碼EF6:爲什麼Count返回0但Find返回一個元素?

using (var db = new DbPerson()) 
{ 
    var b = db.People.Create(); 
    b.Name = "Homer"; 

    db.People.Add(b); 

    Console.WriteLine("Count: {0}", db.People.Count()); 

    foreach (var bb in db.People) 
     Console.WriteLine(bb.Name); 

    var fb = db.People.Find(b.Id); // Id is a GUID generated in the Person ctor 
            // NOT a DB-generated Identity. 
    Console.WriteLine("Found: {0}", fb != null); 

    db.SaveChanges(); 

    Console.WriteLine("Count: {0}", db.People.Count()); 
} 

輸出看起來是這樣的:

Count: 0 
Found: True 
Count: 1 

我看到關於計數不被更新,直到SaveChanges叫其他職位。好的,所以這是「它的工作方式」。

我的問題是具體這個:爲什麼Find返回一個對象從db.PeopleCount()返回0和枚舉器返回沒有元素? FindCount()的行爲是否類似,在返回處於「已添加」狀態的實體之前是否等待SaveChanges

這是什麼原因?我問,因爲我正在編寫一個輕量級的非SQL提供程序,它需要儘可能地反映EF的操作。我找不出什麼邏輯導致Find返回Count()GetEnumerator()沒有的添加元素。我需要解決這些情況。

回答

1

Find()具有特殊質量:它將首先查看已添加但尚未刷新到數據庫的DbContext實體(例如:具有EntityState.Added的實體)。

Count()並且枚舉器將會改爲查看數據庫,在調用SaveChanges()之前顯然沒有任何東西。

Background info

+0

我完全理解這一點。我的問題是爲什麼,我還需要知道哪些地方的新增實體被搜索/包含,以及它們不在哪裏? – Veldaeven

+1

每當您收到意想不到的結果時,我都會假設?例如,這也在[文檔](https://msdn.microsoft.com/en-us/library/gg696418(v = vs.113).aspx)中進行了解釋:「*如果具有給定主鍵的實體值存在於上下文中,然後立即返回,而不會向商店發出請求。*「 –

+0

在閱讀關於'DbSet <>'上的每個方法的文檔之後,以及測試諸如使用'Queryable.FirstOrDefaulit'一個'DbSet',我認爲這就是答案 - Find方法是唯一一個明確聲明返回值來自上下文而不是數據庫的地方。 「保存更改」後,「FirstOrDefault」不會「查找」實體。 – Veldaeven

1

如果你問爲什麼是這樣實現的:Find應該允許通過ID不在數據庫訪問跟蹤的實體。 Find是一個相當特殊的目的方法。也許它也允許檢索被刪除的實體,文檔不會說。 There are other APIs for reaching into the pool of tracked entities as well.

如果你需要搞砸,通常這是EF使用不當的標誌(或者是黑客的標誌)。

NHibernate有一個非常有用的Find:它允許你得到一個實體沒有去數據庫。它返回一個代理。這樣你總是可以傳遞實體對象,幾乎不會有ID。一個很好的抽象。這對於EF來說是不可能的。 Find進入數據庫。

+0

我剛剛測試過它 - 已經被刪除的實體(在SaveChanges之前,處於「已刪除」狀態)也將由Find返回。 – Veldaeven

+0

順便說一句,NHibernate在另一方面很不錯。它會在每個查詢之前自動保存所有更改。這樣數據庫始終保持同步,很難區分上下文結果和數據庫結果之間的差異。 NHibernate的座右銘是持久性的無知。 – usr

相關問題