EF Core 2.0中开启Transaction事务会对DbContext创建和关闭数据库连接的行为有所影响
Posted PowerCoder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF Core 2.0中开启Transaction事务会对DbContext创建和关闭数据库连接的行为有所影响相关的知识,希望对你有一定的参考价值。
数据库
我们先在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方法开启的数据库连接,所以这和没有使用事务的时候是完全不一样的。
以上是关于EF Core 2.0中开启Transaction事务会对DbContext创建和关闭数据库连接的行为有所影响的主要内容,如果未能解决你的问题,请参考以下文章