0

我正在開發一個項目以逐步淘汰遺留應用程序。 在這個過程中,作爲一個臨時解決方案,我們使用數據庫與傳統應用程序集成。實體框架6和悲觀併發

傳統應用程序使用具有可序列化隔離級別的事務。 由於數據庫與遺留應用程序集成,我暫時最好使用相同的悲觀併發模型和可序列化的隔離級別。

這些序列化的事務不僅應該包裝在SaveChanges語句中,還應包含一些數據讀取。

我這樣做是通過

  • 創建一個TransactionScope在我的DbContext與序列化隔離級別。
  • 創建的DbContext
  • 做一些讀
  • 請在的DbContext
  • 呼叫的SaveChanges一些改變對象提交事務範圍(從而節省了變化)

我下這個概念包裝我的整個讀取和寫入序列化事務,然後提交。

我認爲這是一種悲觀併發的方式。

但是,閱讀本文,https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application 指出ef不支持悲觀併發。

我的問題是:

  • 答:是否EF支持我使用串行事務周圍的讀取和寫入
  • B的方式:包裝紙的讀取和一個事務寫入,給我保證,我讀提交事務時數據不會更改。
  • C:這是一種悲觀併發權嗎?

回答

0

該文檔指出EF沒有內置的悲觀併發支持。但這並不意味着你不能用EF來悲觀鎖定。 因此,您可以使用EF進行緊急鎖定!

配方很簡單:

  • 使用交易(不一定是序列化的,因爲它會導致PERF差。) - READCOMMITTED是確定使用......不過要看...
  • 進行更改,請致電dbcontext.savechanges()
  • 確實鎖定了您的表 - 手動執行T-SQL,或者隨意使用代碼att。下面。
  • 給定的T-SQL命令與提示將保持該數據庫鎖定,直到給定事務的持續時間。
  • 您需要注意一件事:您的加載實體可能在您執行鎖定時已經過時,因此鎖定表中的所有實體都應該重新獲取(重新加載)。

我做了很多悲觀鎖定,但樂觀鎖定更好。你不能出錯。

悲觀鎖定無法幫助的一個典型示例是父級子關係,您可能會鎖定父級並將其視爲聚集(因此您認爲您是唯一有權訪問子級的人)。因此,如果其他線程試圖訪問父對象,它將無法工作(將被阻止),直到其他線程從父表釋放鎖。但是對於一個ORM,任何其他編碼器都可以獨立地加載孩子 - 從這一點開始,2個線程將對孩子對象進行更改......悲觀鎖定可能會弄亂數據,樂觀地說你會得到一個例外,你可以重新加載有效的數據,並會盡力再次保存...

因此,代碼:

public static class DbContextSqlExtensions 
{ 
    public static void LockTable<Entity>(this DbContext context) where Entity : class 
    { 
     var tableWithSchema = context.GetTableNameWithSchema<Entity>(); 
     context.Database.ExecuteSqlCommand(string.Format("SELECT null as dummy FROM {0} WITH (tablockx, holdlock)", tableWithSchema)); 
    } 
} 

public static class DbContextExtensions 
{ 
    public static string GetTableNameWithSchema<T>(this DbContext context) 
       where T : class 
    { 
     var entitySet = GetEntitySet<T>(context); 
     if (entitySet == null) 
      throw new Exception(string.Format("Unable to find entity set '{0}' in edm metadata", typeof(T).Name)); 

     var tableName = GetStringProperty(entitySet, "Schema") + "." + GetStringProperty(entitySet, "Table"); 
     return tableName; 
    } 

    private static EntitySet GetEntitySet<T>(DbContext context) 
    { 
     var type = typeof(T); 
     var entityName = type.Name; 
     var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; 

     IEnumerable<EntitySet> entitySets; 
     entitySets = metadata.GetItemCollection(DataSpace.SSpace) 
         .GetItems<EntityContainer>() 
         .Single() 
         .BaseEntitySets 
         .OfType<EntitySet>() 
         .Where(s => !s.MetadataProperties.Contains("Type") 
            || s.MetadataProperties["Type"].ToString() == "Tables"); 
     var entitySet = entitySets.FirstOrDefault(t => t.Name == entityName); 
     return entitySet; 
    } 

    private static string GetStringProperty(MetadataItem entitySet, string propertyName) 
    { 
     MetadataProperty property; 
     if (entitySet == null) 
      throw new ArgumentNullException("entitySet"); 
     if (entitySet.MetadataProperties.TryGetValue(propertyName, false, out property)) 
     { 
      string str = null; 
      if (((property != null) && 
       (property.Value != null)) && 
       (((str = property.Value as string) != null) && 
       !string.IsNullOrEmpty(str))) 
      { 
       return str; 
      } 
     } 
     return string.Empty; 
    } 
} 
+0

感謝您回答我的問題。我的印象是,可串行隔離會爲我鎖定桌子。當我跑了一些測試這似乎也工作。我是否正確地理解了你,保存它不會,我需要手動完成。謝謝 –

+0

可序列化鎖定。但這是最貴的鎖定,所以應該避免。在一個Web應用程序中,如果有超過10個用戶同時請求序列化隔離,那麼他們將互相等待... 如果將有超過5個併發用戶,請避免可序列化。或者至少只限於特殊用途! 我真的建議你嘗試樂觀鎖定 - 它只需要一個額外的領域。唯一的缺點是你可能會遇到需要處理的異常。但樂觀可以與表鎖(我附加的代碼)混合使用。 – baHI

+0

感謝您的回答。我明白這個昂貴的隔離級別的缺點。實際上,我的首選方式確實是樂觀鎖定。就是這樣,因爲我處於過渡期,在一個數據庫上有兩個應用程序,這只是一個臨時解決方案。在我們扼殺舊應用程序之前,我無需更改鎖定級別,只會給項目帶來風險。再次感謝您回答我的問題。 –

0

這是表示EF

http://www.ladislavmrnka.com/2012/09/entity-framework-and-pessimistic-concurrency/

樂觀和悲觀併發的好文章

代碼看起來像...

var options = new TransactionOptions 
{ 
    IsolationLevel = System.Transactions.IsolationLevel.Serializable, 
    Timeout = new TimeSpan(0, 0, 0, 10) 
}; 

using(var scope = new TransactionScope(TransactionScopeOption.RequiresNew, options)) 
{ ... stuff here ...} 

在VS2017看來你必須點擊右鍵,然後TransactionScope的得到它添加一個參考:參考大會\微軟\ Framework.NETFramework \ v4.6.1 \ SYSTEM。 Transactions.dll