數據庫
我們先在SQL Server數據庫中建立一個Book表:
CREATE TABLE [dbo].[Book]( [ID] [int] IDENTITY(1,1) NOT NULL, [BookName] [nvarchar](50) NULL, [BookDescription] [nvarchar](50) NULL, [ISBN] [nvarchar](20) NULL, [CreateTime] [datetime] NULL, CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Book] ADD CONSTRAINT [DF_Book_CreateTime] DEFAULT (getdate()) FOR [CreateTime] GO
然后插入如下數據:
INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Chinese', N'Chinese', N'0001') GO INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'English', N'English', N'0002') GO INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Japanese', N'Japanese', N'0003') GO INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Russian', N'Russian', N'0004') GO INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Italian', N'Italian', N'0005') GO
查詢Book表的數據,如下圖所示:

現在我們使用EF Core將Book表映射到.NET Core控制台項目中的Book實體上,Book實體如下所示:
using System; using System.Collections.Generic; namespace EFCoreDB.Entities { public partial class Book { public int Id { get; set; } public string BookName { get; set; } public string BookDescription { get; set; } public string Isbn { get; set; } public DateTime? CreateTime { get; set; } } }
不使用事務
然后我們在.NET Core控制台項目Program類的Main方法中,使用DbContext(也就是FinanceDigitalToolContext)讀取BookName為"Chinese"的Book實體,然后使用DbContext.SaveChanges方法兩次更改其BookDescription屬性的值,再從數據庫中將其查詢出來顯示,代碼如下:
using EFCoreDB.Entities; using System; using System.Linq; using System.Linq.Expressions; namespace EFCoreDB { class Program { static void Main(string[] args) { using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext()) { Expression<Func<Book, bool>> bookExpression = b => b.BookName == "Chinese";//構造查詢條件,來查詢BookName為Chinese的Book var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName為Chinese的Book實體chineseBook chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫 chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫 chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName為Chinese的Book實體chineseBook //顯示當前chineseBook的當前BookDescription屬性值 Console.WriteLine(chineseBook.BookName + " book has description: \"" + chineseBook.BookDescription + "\""); } Console.WriteLine("Press key to quit...."); Console.ReadLine(); } } }
執行上面的代碼,我們使用EF Core的日志功能,輸出每次DbContext訪問數據庫時的后台日志信息:
首先在執行
var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName為Chinese的Book實體chineseBook
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (129ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Context 'Book' started tracking 'FinanceDigitalToolContext' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished ===============================
從日志中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中開啟了一個數據庫連接,並使用SQL語句做了查詢,然后關閉了數據庫連接。
然后在執行下面的代碼
chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== SaveChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges completed for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Beginning transaction with isolation level 'ReadCommitted'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (86ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Committing transaction. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Disposing transaction. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database. =============================== EF Core log finished ===============================
從日志中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中開啟了一個數據庫連接,並使用SQL語句做了數據庫更改,然后關閉了數據庫連接。然后chineseBook這個Book實體的EntityState從Modified變為了Unchanged。
然后執行代碼
chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== SaveChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges completed for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Beginning transaction with isolation level 'ReadCommitted'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (19ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Committing transaction. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Disposing transaction. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database. =============================== EF Core log finished ===============================
同樣從日志中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中開啟了一個數據庫連接,並使用SQL語句做了數據庫更改,然后關閉了數據庫連接。然后chineseBook這個Book實體的EntityState從Modified變為了Unchanged。
然后執行代碼
chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName為Chinese的Book實體chineseBook
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (21ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished ===============================
從日志中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中還是開啟了一個數據庫連接,並使用SQL語句做了查詢,然后關閉了數據庫連接。
總結下來,上面的代碼和日志發生的事情如下:
- dbContext.Book.First(bookExpression)開啟和關閉了一個數據庫連接,查詢BookName為Chinese的Book實體chineseBook
- 第一個dbContext.SaveChanges()開啟和關閉了一個數據庫連接,更改chineseBook的BookDescription屬性值"This is a Chinese book"到數據庫
- 第二個dbContext.SaveChanges()開啟和關閉了一個數據庫連接,更改chineseBook的BookDescription屬性值"This is a very good Chinese book"到數據庫
- dbContext.Book.First(bookExpression)開啟和關閉了一個數據庫連接,重新查詢BookName為Chinese的Book實體chineseBook
所以綜上所述DbContext一共開啟了和關閉了四個數據庫連接。
使用事務
現在我們更改Program類Main方法中的代碼,將兩次DbContext.SaveChanges方法的調用都放在一個TransactionScope事務范圍中,所以現在兩次DbContext.SaveChanges方法提交的SQL都會在同一個數據庫事務中,代碼如下所示:
using EFCoreDB.Entities; using System; using System.Linq; using System.Linq.Expressions; using System.Transactions; namespace EFCoreDB { class Program { static void Main(string[] args) { using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext()) { Expression<Func<Book, bool>> bookExpression = b => b.BookName == "Chinese";//構造查詢條件,來查詢BookName為Chinese的Book var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName為Chinese的Book實體chineseBook //使用TransactionScope事務范圍來開啟一個數據庫事務 using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew)) { chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務范圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中 chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務范圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中 transactionScope.Complete();//提交TransactionScope事務范圍中的SQL語句到數據庫,數據庫事務結束 } chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName為Chinese的Book實體chineseBook //顯示當前chineseBook的當前BookDescription屬性值 Console.WriteLine(chineseBook.BookName + " book has description: \"" + chineseBook.BookDescription + "\""); } Console.WriteLine("Press key to quit...."); Console.ReadLine(); } } }
執行上面的代碼,我們還是使用EF Core的日志功能,輸出每次DbContext訪問數據庫時的后台日志信息:
首先執行
var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName為Chinese的Book實體chineseBook
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (139ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Context 'Book' started tracking 'FinanceDigitalToolContext' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished ===============================
從日志中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中開啟了一個數據庫連接,並使用SQL語句做了查詢,然后關閉了數據庫連接。
然后執行
using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew)) {
TransactionScope的事務范圍開始,此時數據庫事務已經開始,EF Core沒有輸出日志
然后執行
chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務范圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== SaveChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges completed for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Enlisted in an ambient transaction with isolation level 'Serializable'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (79ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database. =============================== EF Core log finished ===============================
從日志中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中開啟了一個數據庫連接,並使用SQL語句做了數據庫更改,但是沒有關閉數據庫連接。然后chineseBook這個Book實體的EntityState從Modified變為了Unchanged。
然后執行
chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性 dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務范圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== SaveChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges starting for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== DetectChanges completed for 'FinanceDigitalToolContext'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (22ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [Book] SET [BookDescription] = @p0 WHERE [ID] = @p1; SELECT @@ROWCOUNT; =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database. =============================== EF Core log finished ===============================
從日志中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中並沒有開啟新的數據庫連接,而是沿用了上一個DbContext.SaveChanges方法開啟的數據庫連接來提交SQL語句到數據庫。然后chineseBook這個Book實體的EntityState從Modified變為了Unchanged。
然后執行
transactionScope.Complete();//提交TransactionScope事務范圍中的SQL語句到數據庫,數據庫事務結束 }
提交TransactionScope的事務到數據庫,此時數據庫事務結束,TransactionScope的事務范圍也結束,EF Core沒有輸出日志
然后執行
chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName為Chinese的Book實體chineseBook
時,EF Core的日志如下所示:
=============================== EF Core log started =============================== Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Executed DbCommand (24ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN] FROM [Book] AS [b] WHERE [b].[BookName] = N'Chinese' =============================== EF Core log finished =============================== =============================== EF Core log started =============================== A data reader was disposed. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished =============================== =============================== EF Core log started =============================== Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'. =============================== EF Core log finished ===============================
從日志中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中也沒有開啟新的數據庫連接,而是繼續沿用了第一個DbContext.SaveChanges方法開啟的數據庫連接,使用SQL語句做了查詢,之后關閉了第一個DbContext.SaveChanges方法開啟的數據庫連接,所以可以看到第一個DbContext.SaveChanges方法開啟的數據庫連接,現在才被關閉,這和不使用事務時是完全不一樣的。
總結下來,使用事務后的代碼和日志發生的事情如下:
- dbContext.Book.First(bookExpression)開啟和關閉了一個數據庫連接,查詢BookName為Chinese的Book實體chineseBook
- using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew)){開啟了TransactionScope事務范圍,數據庫事務開始
- 第一個dbContext.SaveChanges()開啟一個數據庫連接,但是沒有關閉數據庫連接,更改chineseBook的BookDescription屬性值"This is a Chinese book"到數據庫
- 第二個dbContext.SaveChanges()沒有開啟新的數據庫連接,而是沿用了上一個DbContext.SaveChanges方法開啟的數據庫連接,更改chineseBook的BookDescription屬性值"This is a very good Chinese book"到數據庫
- transactionScope.Complete()提交TransactionScope事務范圍的數據庫事務到數據庫,數據庫事務結束
- }TransactionScope事務范圍結束
- dbContext.Book.First(bookExpression)沒有開啟新的數據庫連接,而是沿用了第一個DbContext.SaveChanges方法開啟的數據庫連接,重新查詢BookName為Chinese的Book實體chineseBook,最后關閉了第一個DbContext.SaveChanges方法開啟的數據庫連接。
所以綜上所述DbContext這次一共只開啟和關閉了兩個數據庫連接,並且第二個數據庫連接執行了三次數據庫操作(兩次DbContext.SaveChanges更改數據,一次Book.First查詢數據)才被關閉。
由此我們可以看到EF Core在處於事務中時,會優化底層開啟和關閉數據庫連接的機制,因為EF Core覺得兩次DbContext.SaveChanges方法提交的SQL語句既然都在同一個事務中,所以就沒有必要每次都開啟和關閉一個數據庫連接,而是沿用了第一次DbContext.SaveChanges方法開啟的數據庫連接,所以這和沒有使用事務的時候是完全不一樣的。
