处理事务的另一种方法是使用System.Transactions。这些类自从.NET Framework 2.0开始就可以使用,但是在.NET Core 1.1中还不可用。在.NET Core2.1中,这些类型又回来了,可以从ADO.NET(从System.Data.SqlClient的4.5版本开始)和Entity Framework Core 2.1中使用。
System.Transactions名称空间为事务定义了几个类。可能最重要的类是Transaction。它可以用于直接访问环境事务,提供关于事务的信息,以及在发生故障时启动回滚。下表描述了Transaction类的成员:
示例应用程序(.NET Core Console App)显示,System.Transactions系统的特性使用了以下依赖项和名称空间:
依赖项
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
System.Data.SqlClient
名称空间
Microsoft.Extensions.Configuration
System
System.Data.SqlClient
System.IO
System.Linq
System.Threading.Tasks
System.Transactions
代码示例定义了一个Utilities类,其中的一些辅助方法在不同示例中使用。
using System;
using System.Linq;
using System.Transactions;
namespace SystemTransactionSamples
{
public class Utilities
{
public static bool AbortTx()
{
Console.WriteLine("Abort the transaction (y/n)?");
return Console.ReadLine().ToLower().Equals("y");
}
public static void DisplayTransactionInformation(string title, TransactionInformation info)
{
if (info == null) throw new ArgumentNullException(nameof(title));
Console.WriteLine(title);
Console.WriteLine($"Creation time: {info.CreationTime:T}");
Console.WriteLine($"Status: {info.Status}");
Console.WriteLine($"Local Id: {info.LocalIdentifier}");
Console.WriteLine($"Distributed Id: {info.DistributedIdentifier}");
}
public static string RandomIsbn() =>
string.Join("",Guid.NewGuid().ToString().ToCharArray().Take(15));
}
}
注意:
示例代码询问用户是否应该终止事务。这适用于演示,但是在实际应用程序的事务中不应该有用户交互。当事务处于活动状态时,锁定记录。我们不希望妨碍其他用户工作,原因是一个用户因为这些锁打开了锁。
还需要注意事务超时。如果用户输入占用的时间超过事务超时时间,事务将被中止。
这个示例使用与前面示例相同的数据库,但是有一个重要的更改。这次Book类型定义为从Books表中映射信息:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Publisher { get; set; }
public string Isbn { get; set; }
public DateTime? ReleaseDate { get; set; }
}
BookData类将Book类型映射到数据库,并实现了AddBookAsync方法,以向Books表添加新记录。该实现与以前在调用ExecuteNonQuety方法插入新记录时看到的实现类似,但有一个重要的区别。这次System.Transactions.Transaction使用SqlConnection方法EnlistTransaction征募。这样,SqlConnection将参与该事务的结果:
public class BookData
{
public async Task AddBookAsync(Book book, Transaction tx)
{
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
string sql = "INSERT INTO [ProCSharp].[Books] ([Title],[Publisher],[Isbn],[ReleaseDate]) "+
"VALUES (@tITLE,@Publisher,@Isbn,@ReleaseDate)";