EF Core无法将SqlServerTransaction强转为IDbTransactionManagerEF异常问题
类型转换失败的核心逻辑非常简单:Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerTransaction是EF Core SqlServer驱动内置的类型,它只实现了微软官方定义的IDbContextTransaction接口,根本不知道你在项目里自定义的IDbTransactionManagerEF接口,自然不可能实现它。
C#做引用类型强转时,校验的是对象运行时的真实类型是否实现了目标接口,和你提前把变量转成IDbContextTransaction父类型没有任何关系——不管你怎么转声明类型,对象本身始终是SqlServerTransaction实例,从来没实现过你的自定义接口,强转必然报错。
最简便、无侵入的方案是实现一个包装类,让包装类实现IDbTransactionManagerEF接口,内部持有EF返回的IDbContextTransaction实例,把接口要求的所有方法、属性全部转发给内部持有的事务实例即可。
步骤1:定义包装类
public class DbTransactionManagerEFWrapper : IDbTransactionManagerEF { private readonly IDbContextTransaction _innerEfTransaction; public DbTransactionManagerEFWrapper(IDbContextTransaction innerEfTransaction) { _innerEfTransaction = innerEfTransaction ?? throw new ArgumentNullException(nameof(innerEfTransaction)); } // 转发IDbContextTransaction接口的所有成员 Guid IDbContextTransaction.TransactionId => _innerEfTransaction.TransactionId; DbTransaction IDbContextTransaction.GetDbTransaction() => _innerEfTransaction.GetDbTransaction(); void IDbContextTransaction.Commit() => _innerEfTransaction.Commit(); Task IDbContextTransaction.CommitAsync(CancellationToken cancellationToken = default) => _innerEfTransaction.CommitAsync(cancellationToken); void IDbContextTransaction.Rollback() => _innerEfTransaction.Rollback(); Task IDbContextTransaction.RollbackAsync(CancellationToken cancellationToken = default) => _innerEfTransaction.RollbackAsync(cancellationToken); void IDisposable.Dispose() => _innerEfTransaction.Dispose(); ValueTask IAsyncDisposable.DisposeAsync() => _innerEfTransaction.DisposeAsync(); // 补全自定义IDbTransactionManager接口要求的所有成员,按实际业务逻辑实现即可 }
步骤2:使用包装类替代直接强转
不需要再做任何类型强转,直接把EF返回的事务实例传入包装类构造函数即可:
IDbContextTransaction contextTransaction = this._dbContext.Database.BeginTransaction(); this._CommandContextEF.DbTransaction = new DbTransactionManagerEFWrapper(contextTransaction);
其他可选方案
如果你需要所有调用_dbContext.Database.BeginTransaction()的地方都直接返回IDbTransactionManagerEF类型,可以替换EF Core内部的IDbTransactionCreator服务注册,在自定义的事务创建器中直接返回你实现的IDbTransactionManagerEF实例。但这个方案需要深入EF Core内部服务注册逻辑,改动成本更高,非特殊需求不推荐使用。
内容的提问来源于stack exchange,提问作者quanchinhong

