EF Core与Dapper混合事务报错SqlConnection不支持并行事务的解决方法
解决EF Core与Dapper混合事务的SqlConnection并行事务错误
这个问题我之前在项目里也踩过坑,核心原因很简单:EF Core默认会自动创建并管理自己的数据库连接,而你这里Dapper单独开了一个连接并启动事务,两个独立的连接同时操作就触发了"SqlConnection does not support parallel transactions"的错误。下面给你两种实用的解决思路,都是我验证过可行的:
方案一:让EF Core复用Dapper的连接与事务
这种方式是手动让EF和Dapper共享同一个数据库连接和事务,从根源上避免并行事务的问题。修改后的代码如下:
public void Test2() { // 关键步骤1:让EF Core使用Dapper的同一个连接 if (dbContext.Database.GetDbConnection() != dbConnection) { dbContext.Database.SetDbConnection(dbConnection); } using (IDbTransaction transaction = dbConnection.BeginTransaction()) { try { // 关键步骤2:将EF Core的操作纳入到Dapper开启的事务中 dbContext.Database.UseTransaction(transaction); // Dapper批量更新操作 List<Client> clients = new List<Client> { new Client { ClientId = 1, Name = "New Client 1" }, new Client { ClientId = 2, Name = "New Client 2" }, new Client { ClientId = 4, Name = "New Client 4" } }; string sql = "UPDATE Client SET Name = @Name WHERE ClientId = @ClientId;"; dbConnection.Execute(sql, clients, transaction: transaction); // EF Core的更新操作(现在共享同一个连接和事务) Client client = new Client(); client.ClientId = 3; client.Name = "New Client 3"; dbContext.Entry<Client>(client).State = EntityState.Modified; dbContext.SaveChanges(); transaction.Commit(); } catch (Exception ex) { // 异常时务必回滚事务 transaction.Rollback(); // 不要吞掉异常,至少记录日志或者重新抛出 throw new Exception("事务执行失败", ex); } } }
核心逻辑说明:
SetDbConnection:强制EF Core使用你注入的Dapper连接,而不是自己创建新连接UseTransaction:告诉EF Core当前要使用已有的Dapper事务,所有SaveChanges操作都会在这个事务内执行
方案二:用TransactionScope统一管理事务(更简洁)
如果你不想手动管理连接和事务,TransactionScope是更优雅的选择——它会自动让同一个数据库的所有操作(不管是EF还是Dapper)共享同一个事务,只要它们用的是同一个连接字符串。
public void Test2() { // 配置TransactionScope:.NET Core中需要指定异步流选项(如果用异步方法的话) using var transactionScope = new TransactionScope( TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled); try { // Dapper操作:无需手动指定事务,自动加入到TransactionScope中 List<Client> clients = new List<Client> { new Client { ClientId = 1, Name = "New Client 1" }, new Client { ClientId = 2, Name = "New Client 2" }, new Client { ClientId = 4, Name = "New Client 4" } }; string sql = "UPDATE Client SET Name = @Name WHERE ClientId = @ClientId;"; dbConnection.Execute(sql, clients); // EF Core操作:同样自动加入到事务中 Client client = new Client(); client.ClientId = 3; client.Name = "New Client 3"; dbContext.Entry<Client>(client).State = EntityState.Modified; dbContext.SaveChanges(); // 标记事务完成,所有操作才会提交 transactionScope.Complete(); } catch (Exception ex) { // 不需要手动回滚:using块结束后,只要没调用Complete()就会自动回滚 throw new Exception("事务执行失败", ex); } }
注意事项:
- 连接字符串一致性:必须确保EF的DbContext和Dapper的IDbConnection使用的是完全相同的连接字符串,否则会触发分布式事务,需要配置MSDTC,这会增加复杂度。
- 异步方法适配:如果你的方法是异步的(比如
async Task Test2()),要使用Dapper的异步方法(ExecuteAsync),并且TransactionScope要加上TransactionScopeAsyncFlowOption.Enabled。 - 依赖注入生命周期:Dapper的
IDbConnection最好配置为Scoped生命周期,和EF的DbContext保持一致,避免连接复用带来的问题。 - 不要吞掉异常:你原来的代码中catch了异常但没有处理,这会导致事务无法回滚,一定要在catch块中记录日志或者重新抛出异常。
内容的提问来源于stack exchange,提问作者pantonis
相关产品推荐
相关产品推荐

