- SaveChange()、Database.ExecuteSqlCommand()
- BeginTransaction()
環境建置
在 AdventureWorks2019 內建立 EFTransaction Table 來存放資料,並開啟 SQL Profile 來觀察交易
EFTransacton Table Script
USE [AdventureWorks2019]
GO
CREATE TABLE [dbo].[EFTransaction]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[RecordTime] [datetime] NULL,
CONSTRAINT [PK_EFTransaction] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
)
Profile 內開啟交易事件
SaveChange()、Database.ExecuteSqlCommand()
SaveChange() 和 Database.ExecuteSqlCommand() 預設都會開啟交易,隔離層級為資料庫預設層級,以 MS SQL 為例,預設隔離層級是 read committed
DbFirstDbContext dbFirstDbContext = new DbFirstDbContext();
dbFirstDbContext.EFTransaction.Add(new EFTransaction() { RecordTime = DateTime.Now });
dbFirstDbContext.SaveChanges();
string TSQL = "DELETE FROM EFTransaction WHERE RecordTime < getdate()";
dbFirstDbContext.Database.ExecuteSqlCommand(TSQL);
從下圖 profile 截圖可以觀察到,SaveChange() 和 Database.ExecuteSqlCommand() 都包在各自的交易內,且從 Audit Login 內可以看到 read committedBeginTransaction() 可以把多個資料庫操作包在同一個交易內,以上述的 SaveChange() 和 Database.ExecuteSqlCommand() 來觀察
using (DbFirstDbContext dbFirstDbContext = new DbFirstDbContext())
using (DbContextTransaction tran = dbFirstDbContext.Database.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
dbFirstDbContext.EFTransaction.Add(new EFTransaction() { RecordTime = DateTime.Now });
dbFirstDbContext.SaveChanges();
string TSQL =
"insert into EFTransaction (RecordTime)" +
" values(getdate())";
dbFirstDbContext.Database.ExecuteSqlCommand(TSQL);
tran.Commit();
}
從下圖 profile 截圖可以觀察到,SaveChange() 和 Database.ExecuteSqlCommand() 的 insert 動作都包在同一個交易內,且從 Audit Login 內可以看到 read committed
另外透過 BeginTranaction() 來開啟交易,是可以明確指定交易層級的,該範例雖然有明確指定 read committed,但 read committed 是預設值
Database.BeginTransaction() will open the connection if it is not already opened. If DbContextTransaction opened the connection then it will close it when Dispose() is called.