Entity Framework 併發處理

来源:http://www.cnblogs.com/liubibi23/archive/2017/01/16/6290176.html
-Advertisement-
Play Games

參考頁面: http://www.yuanjiaocheng.net/entity/entity-relations.html http://www.yuanjiaocheng.net/entity/entity-lifecycle.html http://www.yuanjiaocheng.net ...


參考頁面:

http://www.yuanjiaocheng.net/entity/entity-relations.html

http://www.yuanjiaocheng.net/entity/entity-lifecycle.html

http://www.yuanjiaocheng.net/entity/code-first.html

http://www.yuanjiaocheng.net/entity/mode-first.html

http://www.yuanjiaocheng.net/entity/database-first.html

什麼是併發?

併發分悲觀併發和樂觀併發。

悲觀併發:比如有兩個用戶A,B,同時登錄系統修改一個文檔,如果A先進入修改,則系統會把該文檔鎖住,B就沒辦法打開了,只有等A修改完,完全退出的時候B才能進入修改。

樂觀併發:同上面的例子,A,B兩個用戶同時登錄,如果A先進入修改緊跟著B也進入了。A修改文檔的同時B也在修改。如果在A保存之後B再保存他的修改,此時系統檢測到資料庫中文檔記錄與B剛進入時不一致,B保存時會拋出異常,修改失敗。

EF中如何控制併發?

Entity Framework不支持悲觀併發,只支持樂觀併發。

如果要對某一個表做併發處理,就在該表中加一條Timestamp類型的欄位。註意,一張表中只能有一個Timestamp的欄位。

Data Annotations中用Timestamp來標識設置併發控制欄位,標識為Timestamp的欄位必需為byte[]類型。

public class Person
    {
        public int PersonId { get; set; }
        public int SocialSecurityNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [Timestamp]
        public byte[] RowVersion { get; set; }
    }

Fluent API用IsRowVersion方法

modelBuilder.Entity<Person>().Property(p => p.RowVersion).IsRowVersion();

我們看到生成的資料庫中,RowVersion是timestamp類型。

下麵我們寫一段代碼來測試一下:

       static void Main(string[] args)
        {
            var person = new Person
            {
                FirstName = "Rowan",
                LastName = "Miller",
                SocialSecurityNumber = 12345678
            };
            //新增一條記錄,保存到資料庫中
            using (var con = new BreakAwayContext())
            {
                con.People.Add(person);
                con.SaveChanges();
            }

            var firContext = new BreakAwayContext();
            //取第一條記錄,並修改一個欄位:這裡是修改了FirstName
            //先不保存
            var p1 = firContext.People.FirstOrDefault();
            p1.FirstName = "Steven";

            //再創建一個Context,同樣取第一條記錄,修改LastName欄位並保存
            using (var secContext = new BreakAwayContext())
            {
                var p2 = secContext.People.FirstOrDefault();
                p2.LastName = "Francis";
                secContext.SaveChanges();
            }
            try
            {
                firContext.SaveChanges();
                Console.WriteLine(" 保存成功");
            }
            catch (DbUpdateConcurrencyException ex)
            {
                Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失敗");
            }
            Console.Read();
        }

上面我們實例化了三個DbContext,第一個增加一條記錄到資料庫中,第二個修改剛增加的記錄但不保存,然後第三個Context也取剛新增的記錄並保存,最後再保存第二個Context,結果保存失敗。

可以看到我們的併發控制取到了作用。

分析EF生成的SQL語句:

exec sp_executesql N'update [dbo].[People]
set [LastName] = @0
where (([PersonId] = @1) and ([RowVersion] = @2))
select [RowVersion]
from [dbo].[People]
where @@ROWCOUNT > 0 and [PersonId] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8)',@0=N'Francis',@1=1,@2=0x00000000000007D1

可以看到,它在取對應記錄的時候把RowVersion也作為篩選條件。上面例子中的secContext保存的時候,資料庫中的RowVersion欄位的值就變了,所以firContext保存的時候用原來的RowVersion取值,自然就取不到相應的記錄而報錯。

如果我們只是要對某個欄位作併發控制呢?彆著急,EF也有辦法。

Data Annotations中用ConcurrencyCheck來標識

 public class Person
    {
        public int PersonId { get; set; }
        [ConcurrencyCheck]
        public int SocialSecurityNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public byte[] RowVersion { get; set; }
    }

Fluent API用IsConcurrencyToken方法

modelBuilder.Entity<Person>().Property(p => p.SocialSecurityNumber).IsConcurrencyToken();

上面的實體中,我們將SocialSecurityNumber(社會保險號)標識為開放式併發,也寫一個類似的代碼測試一下:

 static void Main(string[] args)
        {
            var person = new Person
            {
                FirstName = "Rowan",
                LastName = "Miller",
                SocialSecurityNumber = 12345678
            };
            //新增一條記錄,保存到資料庫中
            using (var con = new BreakAwayContext())
            {
                con.People.Add(person);
                con.SaveChanges();
            }

            var firContext = new BreakAwayContext();
            //取第一條記錄,並修改SocialSecurityNumber欄位
            //先不保存
            var p1 = firContext.People.FirstOrDefault();
            p1.SocialSecurityNumber = 123;

            //再創建一個Context,同樣取第一條記錄,
            //修改SocialSecurityNumber欄位並保存
            using (var secContext = new BreakAwayContext())
            {
                var p2 = secContext.People.FirstOrDefault();
                p2.SocialSecurityNumber = 456;
                secContext.SaveChanges();
            }
            try
            {
                firContext.SaveChanges();
                Console.WriteLine(" 保存成功");
            }
            catch (DbUpdateConcurrencyException ex)
            {
                Console.WriteLine(ex.Entries.First().Entity.GetType().Name + " 保存失敗");
            }
            Console.Read();
        }

運行結果同樣是保存失敗,說明我們的併發控制起作用了。

分析一下EF執行的SQL:

exec sp_executesql N'update [dbo].[People]
set [SocialSecurityNumber] = @0
where (([PersonId] = @1) and ([SocialSecurityNumber] = @2))
',N'@0 int,@1 int,@2 int',@0=123,@1=1,@2=12345678

可以看到,EF將我們要併發控制的列SocialSecurityNumber也作為一個篩選條件,這樣firContext保存的時候也會因為的資料庫中SocialSecurityNumber值變了,取不到對應的記錄而更新失敗。

 補充一下:如果是EDMX如何將欄位設置為Concurrency。很簡單,在對應的欄位上右鍵-屬性。在打開的屬性視窗中有一個併發模式,你將它選擇為Fixed即可。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 代理delegate: 對象引用指向某個特定類型的對象。 代理指向某個特定類型的方法。 代理四步: 定義自定義代理類:public delegate void first(int i); 實例化代理類:first MyDelegate = null; 實例添加方法:MyDelegate += new... ...
  • AspectCore Project 介紹 什麼是AspectCore Project ? "AspectCore Project" 是適用於 "Asp.Net Core" 平臺的輕量級 "Aop(Aspect oriented programming)" 解決方案,它更好的遵循Asp.Net Co ...
  • 本文版權歸博客園和作者吳雙本人共同所有. 寫在前面 這是一個數據爆發的網路時代,大家習慣於瀏覽圖文直觀帶給我們的快速信息。大圖片的存儲和瀏覽經常會成為Web伺服器的瓶頸。試想如果你的Web伺服器依然將大量圖片存儲在其本地,而單頁面主要的信息在於圖片列表,在訪問量增長後,一定會面臨帶寬、磁碟IO的瓶頸 ...
  • 參考頁面: http://www.yuanjiaocheng.net/ASPNET-CORE/core-middleware.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-exception.html http://www.yuanjiaoch ...
  • 參考頁面: http://www.yuanjiaocheng.net/webapi/first.html http://www.yuanjiaocheng.net/webapi/web-api-gaisu.html http://www.yuanjiaocheng.net/webapi/create ...
  • 參考頁面: http://www.yuanjiaocheng.net/ASPNET-CORE/project-layout.html http://www.yuanjiaocheng.net/ASPNET-CORE/projectjson.html http://www.yuanjiaocheng. ...
  • 參考頁面: http://www.yuanjiaocheng.net/entity/entity-relations.html http://www.yuanjiaocheng.net/entity/entity-lifecycle.html http://www.yuanjiaocheng.net ...
  • 參考頁面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-delete.html http://www.yuanjiaocheng.net/webapi/Consume-web-api.html http://www.yuanjiaoch ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...