arch / UnitOfWork

A plugin for Microsoft.EntityFrameworkCore to support repository, unit of work patterns, multiple database with distributed transaction supported, and MySQL multiple databases/tables sharding supported.
MIT License
1.34k stars 343 forks source link

SaveChangesAsync(bool ensureAutoHistory = false, params IUnitOfWork[] unitOfWorks)这个怎么使用 #122

Open panda-big opened 4 years ago

panda-big commented 4 years ago

SaveChangesAsync(bool ensureAutoHistory = false, params IUnitOfWork[] unitOfWorks) 这个怎么使用?

我这边直接传IIUnitOfWork 报错:

TransactionScope必须在同一创建线程上

rigofunc commented 4 years ago

什么应用程序?web还是wpf?如果是web的话,默认每个就是Request Scope的呀

panda-big commented 4 years ago

是web,我有2个上下文对象是不同数据库的,例如: private readonly IUnitOfWork<BusinessDbContext> _businessUnitOfWork; private readonly IUnitOfWork<SysManageDbContext> _sysmanageUnitOfWork; private readonly IConfiguration Configuration; public HomeService(IUnitOfWork<BusinessDbContext> businessUnitOfWork, IUnitOfWork<SysManageDbContext> sysmanageUnitOfWork, IConfiguration configuration) { _businessUnitOfWork = businessUnitOfWork; _sysmanageUnitOfWork = sysmanageUnitOfWork; Configuration = configuration; } 当我把 _businessUnitOfWork 和 _sysmanageUnitOfWork 放进数组进行保存的时候 就会报错。

panda-big commented 4 years ago

//add UnitOfWork services.AddUnitOfWork<SysManageDbContext, BusinessDbContext>()

rigofunc commented 4 years ago

数据库是不同机器还是相同机器上的?

panda-big commented 4 years ago

是不同机器上的mysql数据库,我查了相关资料是因为使用了 await 的问题,需要如下使用:

using(var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { //todo }

加上这个测试之后发现 还是报错,错误如下: Microsoft.EntityFrameworkCore.Update[10000] An exception occurred in the database while saving changes for context type 'Infrastructure.BusinessRepository.BusinessDbContext'. System.InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected. The current provider does not support ambient transactions. See http://go.microsoft.com/fwlink/?LinkId=800142'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.AmbientTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'. at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition.Log[TLoggerCategory](IDiagnosticsLogger1 logger, WarningBehavior warningBehavior, Exception exception) at Microsoft.EntityFrameworkCore.Internal.RelationalLoggerExtensions.AmbientTransactionWarning(IDiagnosticsLogger1 diagnostics, IRelationalConnection connection, DateTimeOffset startDate) at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.HandleAmbientTransactions() at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext , ValueTuple2 parameters, CancellationToken cancellationToken) at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList1 entriesToSave, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) System.InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected. The current provider does not support ambient transactions. See http://go.microsoft.com/fwlink/?LinkId=800142'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.AmbientTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'. at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition.Log[TLoggerCategory](IDiagnosticsLogger1 logger, WarningBehavior warningBehavior, Exception exception) at Microsoft.EntityFrameworkCore.Internal.RelationalLoggerExtensions.AmbientTransactionWarning(IDiagnosticsLogger1 diagnostics, IRelationalConnection connection, DateTimeOffset startDate) at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.HandleAmbientTransactions() at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext , ValueTuple2 parameters, CancellationToken cancellationToken) at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList1 entriesToSave, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

也就是说在.net core 里面已经不能使用TransactionScope 作为分布式事务的解决方案。 我也查看了相关资料说从.NET core 2.1 开始已经不再支持分布式事务因为移除了windows的 mstsc 远程。 所以这段代码的意义也就不存在了: ///

/// Saves all changes made in this context to the database with distributed transaction. /// /// True if save changes ensure auto record the change history. /// An optional array. /// A that represents the asynchronous save operation. The task result contains the number of state entities written to database. public async Task SaveChangesAsync(bool ensureAutoHistory = false, params IUnitOfWork[] unitOfWorks) { using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var count = 0; foreach (var unitOfWork in unitOfWorks) { count += await unitOfWork.SaveChangesAsync(ensureAutoHistory); }

            count += await SaveChangesAsync(ensureAutoHistory);

            ts.Complete();

            return count;
        }
    }
panda-big commented 4 years ago

目前框架就不支持分布式事务了

rigofunc commented 4 years ago

应该就是这个原因了,我已经几年没有写C#了,囧

panda-big commented 4 years ago

现在搞java了?

panda-big commented 4 years ago

我有个想法 想把查询表达式的条件封装类集成进来 达到可以根据自己组装条件的效果,例如: //构造查询表达式 var PredicateBuilder = PredicateBuilder.Instance; PredicateWrap expression = null; if (!string.IsNullOrEmpty(roleRequestModel.StartTime)) { expression &= PredicateBuilder.Equal(p => p.StartTime, Convert.ToDateTime(roleRequestModel.StartTime)); } if (!string.IsNullOrEmpty(roleRequestModel.EndTime)) { expression &= PredicateBuilder.Equal(p => p.EndTime, Convert.ToDateTime(roleRequestModel.EndTime)); }
list = await repository.GetPagedListAsync( predicate: expression, orderBy: a => a.OrderByDescending(b => b.CreateTime), pageIndex: roleRequestModel.PageCurrent, pageSize: roleRequestModel.PageSize);

rigofunc commented 4 years ago

你可以提交一个PR,我看一下

panda-big commented 4 years ago

后续 我抽时间去弄,因为 我已经在我的项目里面用了,提交了我在告诉你。

tanher commented 3 years ago

所以这个问题不解决了吗?现在代码还是没变,但 .net core 已经到 5.0 了,现在还在报错: A TransactionScope must be disposed on the same thread that it was created.

panda-big commented 3 years ago

这个分布式事务,在core里面已经不能使用了。我是下载的源代码去掉了。