Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2447

控制EF的Transaction範圍

$
0
0

被問到在EF環境要如何控制將某些DB操作包含在Transaction範圍內、將某些排除在外? 整理成簡單範例方便說明。

範例程式碼共有三段DB操作,第一段是寫入追蹤資訊到ActLog資料表、第二、三段則是各寫入一筆Player資料,為了模擬交易Rollback情境,故意讓兩筆Player的Primary Key相同。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
 
namespace TestNoTran
{
class Program
    {
staticvoid Main(string[] args)
        {
using (TransactionScope tx = new TransactionScope())
            {
try
                {   //...其他程式邏輯(省略)...
                    SomeLogHelper.Log("Debug: Insert To DB");
                    SomeDALHelper.InsertPlayer("A1", "U1", DateTime.Today, 100);
//故意寫入PK相同的第二筆資料,將引發錯誤
                       SomeDALHelper.InsertPlayer("A1", "U2", DateTime.Today, 120);
                    tx.Complete();
                }
catch (Exception ex)
                {
                    Console.WriteLine("Error: {0}", ex.Message);
                }
                Console.Read();
            }
 
        }
    }
 
class SomeDALHelper
    {
publicstaticvoid InsertPlayer(
string id, string name, DateTime regDate, int score)
        {
using (var ctx = new LabEntities())
            {
                var p1 = new Player()
                {
                    UserId = id,
                    UserName = name,
                    RegDate = regDate,
                    Score = score
                };
                ctx.Players.Add(p1);
                ctx.SaveChanges();
            }
        }
    }
 
class SomeLogHelper 
    {
publicstaticvoid Log(string msg)
        {
using (var ctx = new LabEntities())
            {
                ctx.ActLogs.Add(new ActLog()
                {
                    Info = msg
                });
                ctx.SaveChanges();
            }
        }
    }
}

執行程式,一如預期,會得到因PK重複引發的錯誤:

Error: System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_Player'. Cannot insert duplicate key in object 'dbo.Player'. The duplicate key value is (A1).

檢查資料庫,ActLog及Player資料表均空空如也,代表三個DB動作一起Rollback了。如果我們希望寫ActLog的部分不要參與交易,無論如何都將資訊寫入資料庫,該怎麼做?

最簡單的做法是用另一個TransactionScope將寫ActLog部分包起來,並指定初始化參數為TransactionScopeOption.Suppress,宣告在此範圍內的DB動作不需要參與交易。如下:

staticvoid Main(string[] args)
        {
using (TransactionScope tx = new TransactionScope())
            {
try
                {   //...其他程式邏輯(省略)...
//宣告出一段不參與交易的範圍
using (TransactionScope tx2 = 
new TransactionScope(TransactionScopeOption.Suppress))
                    {
                        SomeLogHelper.Log("Debug: Insert To DB");
                    }
                    SomeDALHelper.InsertPlayer("A1", "U1", DateTime.Today, 100);
//故意寫入PK相同的第二筆資料,將引發錯誤
    SomeDALHelper.InsertPlayer("A1", "U2", DateTime.Today, 120);
                    tx.Complete();
                }
catch (Exception ex)
                {
                    Console.WriteLine("Error: {0}", ex.ToString());
                }
                Console.Read();
            }
 
        }

重新執行程式,錯誤依舊,Player資料表仍無資料,但ActLog資料表會留下一筆記錄,實現了排除在交易範圍外的目標。

最後補充,除了使用TransactionScope外,還有其他處理EF交易的方式,如: 讓DbContext.SaveChanges()自動將一連串動作包成交易、讓多個DbContext共用連線並控制該連線交易狀態等,細節可參考舊文,該文談的雖是LINQ to SQL,但與EF運作原理大同小異。


Viewing all articles
Browse latest Browse all 2447

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>