2013-06-18 31 views
1

我添加帖子到我的數據庫時有問題,這個「添加」功能從多個線程中調用。通常在彼此之後很快,我不知道這是否重要,但它是如何工作的。InvalidOperationException當保存到數據庫

代碼:

private object dbLock = new object(); 

public void Add(string fileName, DateTime collectionTime) 
    { 
     try 
     { 
      lock (dbLock) 
      { 
       var collection = new Collection 
       { 
        Filename = fileName, 
        Datetime = collectionTime, 
       }; 
       _entities.AddToCollection(collection); 
       _entities.SaveChanges(); 
       CollectionChanged(collection, null); 
      } 
     } 
     catch (Exception ex) 
     { 
     } 
     finally 
     { 

     } 
    } 

我的問題是,當調用SaveChanges我得到這個異常:更新對象

到數據庫的更改被成功提交,但出現 錯誤上下文。 ObjectContext的狀態可能不一致。內部異常 消息:由於對象的鍵 值與ObjectStateManager中的另一個對象衝突,因此AcceptChanges無法繼續。使用 確保在調用AcceptChanges之前鍵值是唯一的。

我設法找到所有的答案有事情做與你必須添加StoreGeneratedPattern="Identity",我媒體鏈接這樣做,但它並不能幫助

<Property Name="ID" Type="integer" Nullable="false" StoreGeneratedPattern="Identity" /> 

那麼,有沒有其他的方式來解決這個?

+0

「不一致」總是表示進程尚未完全終止ist工作。如果您正在使用多個線程訪問您的數據庫,則DBMS必須能夠處理此問題,或者您的代碼必須是線程安全的 –

+0

使用來自多個線程的對象上下文通常意味着*非常糟糕*正在發生 - 即* *不是**的預期用法,並可能導致非常糟糕的事情。吞下異常也是一個非常糟糕的主意。你可以擴展這裏的場景嗎?這是什麼樣的應用程序,爲什麼它在線程之間共享對象上下文? –

回答

2

最終,共享線程之間的對象上下文是一個不錯的想法真的很壞主意。一個對象上下文旨在用作工作單元 - 即短暫的;典型應用:

using(var ctx = new SomeObjectContextType()) // assuming IDisposable 
{ 
    // not shown: get some records, if needed 
    ... 
    // not shown: update, add, remove some records, if needed 

    ctx.SaveChanges(); 
} // and now it is gone, never to be used again 

它可能會比在一些情形下更復雜,例如保持一個對象的上下文頁/請求的時間,但它應該被共享呼叫者。原因很多,但基本上所有競爭更新都需要鎖定,這裏的「更新」包括從數據庫中讀取任何記錄或者延遲加載屬性的簡單行爲。當多個線程訪問時,對象上下文變得不穩定並不令人驚訝:該場景不是(通常)支持

此外,還有與具有長壽命的對象範圍內的其他問題:

  • 偶爾,事情變壞(例如超時,死鎖,回滾,或只是一個簡單的連接錯誤);這裏適當的迴應方法就是簡單地丟棄你現在破碎的對象上下文(如果合適的話,Dispose()) - 並且忘掉它;如果您想重新應用您的更改,您可以從新鮮對象上下文
  • 對象上下文包括標識映射和變更管理系統;如果你把它保存的時間比單次操作的時間要長,你就會慢慢積累越來越多的物體。除了造成內存問題之外,這會逐漸降低性能 - 因爲每一次讀取/更新操作現在都有越來越多的數據需要拖網穿越

基本上,這裏的「修復」是:不要那樣做。這不是對象上下文的正確用法。沒有應用程序範圍的共享對象上下文。

+0

謝謝!這看起來很有效,如果我喜歡這樣,我甚至可以跳過我的鎖嗎? – Nick3

+1

@ Nick3是;如果沒有共享對象上下文,就沒有理由同步 –