LINQ與EF的並發處理


 

 public class Person
{
     public int Id { get; set; }
     public string Name { get; set; }
     
     [Timestamp]
     public Byte[] Version { get; set; }
}

 

LINQ和EF的並發控制,都是在其生成的SQL語句中的 where 加入時間戳字段作為查詢條件進行控制的,如:

EF 自動生成的SQL:

 

exec sp_executesql N'UPDATE [dbo].[People]
SET [Name] = @0
WHERE (([Id] = @1) AND ([Version] = @2))
SELECT [Version]
FROM [dbo].[People]
WHERE @@ROWCOUNT > 0 AND [Id] = @1',
N'@0 nvarchar(max) ,@1 int,@2 binary(8)',@0=N'my name',@1=1,@2=0x0000000000000BBF

 

最后返回 [Version] 更新記錄。

 

在 LINQ 的 dbml 中每個實體的字段屬性的更新檢查都是默認為始終的,即會默認產生並發沖突。

  LINQ 並發的解決方法:

try {  

    //如果發生並發沖突,將繼續處理,進入 catch 進行處理方案選擇

    db.SubmitChanges(ConflictMode.ContinueOnConflict);

    //或FailOnFirstConflict,這種一般不會進行方案選擇,因為它在第一次有並發沖突時,就停止嘗試更新,

    //而ContinueOnConflict則會嘗試更新所有更新,並累積和返回所有並發沖突。

  } catch (ChangeConflictException) {  

    foreach (ObjectChangeConflict occ in db.ChangeConflicts)  {   

 

        //相關的邏輯代碼

        // LINQ的實體對象通過 occ.Object 獲取

        // 數據庫元表通過 db.Mapping.GetTable(occ.Object.GetType()) 獲取

        // 沖突成員通過 occ.MemberConflicts 獲取,在其中可以獲得 :

        // 沖突成員的當前值(CurrentValue)、沖突成員的原始值(OriginalValue)、沖突成員的數據庫值(DatabaseValue)

        // 可以根據上面邏輯代碼在以下三種方案選擇其一:(成員也可以有自己的解決方案)

       // 1. 以數據庫的值為准 

        //occ.Resolve(RefreshMode.OverwriteCurrentValues);

        // 2. 以LINQ實體對象的值為准

        //occ.Resolve(RefreshMode.KeepCurrentValues);

         // 3. 只更新LINQ實體對象中改變的字段的值,其他的保留不變   

       //occ.Resolve(RefreshMode.KeepChanges);  

      }

     //最后再次更新數據庫 

     data.SubmitChanges();

}

還有一種解決辦法,就是通過事務處理,不作並發沖突方案選擇,如發生並發異常,就直接回滾。

using (TransactionScope scope = new TransactionScope())
{

  db.SubmitChanges();

  scope.Complete();

}

 

在 EF 的 edmx 或 model 中的每個實體的字段屬性的並發模式都是默認為None的,即不會默認產生並發沖突。

如要處理並發沖突,則如下操作:(需要才設置)

1. 在 edmx 中每個實體的字段屬性的並發模式設置為Fixed

2. 在 model 中的某個字段屬性上加 Timestamp 特性(每個實體只能有一個)或 ConcurrencyCheck特性。

  並發的解決辦法:

  

  try{   

      context.SaveChanges();

    }

    catch (OptimisticConcurrencyException ex){

        // 沖突成員實體通過 ex.StateEntries 獲取

        // 同樣邏輯代碼可以 根據 ObjectStateEntry xxx 對象進行操作

         // 可以根據上面邏輯代碼在以下兩種方案選擇其一:

        // 以實體對象為准

        // context.Refresh(RefreshMode.ClientWins, xxx);

          // 以數據庫為准

        // context.Refresh(RefreshMode.StoreWins,xxx); 

        //最后再次更新數據庫

        context.SaveChanges();

    }

 

    還有LINQ的事務解決辦法同樣適合EF。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM