EF Core并行更新事务无异常但数据未更新,求排查方案
问题
我是Entity Framework Core新手,需要批量更新多个产品的若干字段(详见代码中的updateFieldList变量),且每个更新必须通过ExecuteSqlRawAsync调用存储过程生成变更日志(ERP系统强制要求)。单线程运行时代码正常,但533个产品要耗时约5分钟,所以尝试用Tasks并行优化。我知道多任务不能共用同一个DbContext,参考官方文档写了下面的代码,但现在代码无异常但数据完全没更新,求排查方向。
public async Task<Result> UpdateProductStatus(List<DTO.QueryResult> productsUpdateList, Vorlauf newProductStatus, string changeReason) { try { var updateFieldList = new List<FieldUpdate>() { new FieldUpdate("Prodstat", newProductStatus.Nummer), new FieldUpdate("_Date", DateTime.Now), new FieldUpdate("_User", Environment.UserName) }; if(changeReason.Trim() != string.Empty) { updateFieldList.Add(new FieldUpdate("Stchinfo", changeReason)); } if (newProductStatus.Log5 == 1) { updateFieldList.Add(new FieldUpdate("Sperr", (byte)1)); } using var connection = new SqlConnection(Connection.GetImpGgConnectionString()); var options = new DbContextOptionsBuilder<IMP_GG_Context>() .UseSqlServer(connection) .Options; using var context1 = new IMP_GG_Context(connection); using (var transaction = context1.Database.BeginTransaction()) { var predicate = PredicateBuilder.New<Artikel>(); foreach (var product in productsUpdateList) { predicate = predicate.Or(artikel => artikel._Kenn == product.ProductId); } var products = context1.ArtikelTable.Where(predicate).ToList(); List<Task> tasks = new List<Task>(); foreach (var product in products) { var task = Task.Run(() => { using(var context2 = new IMP_GG_Context(connection)) { context2.Database.UseTransaction(transaction.GetDbTransaction()); foreach (FieldUpdate fieldUpdate in updateFieldList) { var updateResult = UpdateArtikel(product, fieldUpdate); Changelog changelog = new Changelog(product, fieldUpdate.DatabaseFieldName.ToUpper(), fieldUpdate.OldValue.ToString(), fieldUpdate.NewValue.ToString()); string changeLogQuery = changelog.CreateQuery; var parameters = changelog.GetSqlParameterList(); var result = _Context.Database.ExecuteSqlRawAsync(changeLogQuery, parameters); context2.SaveChanges(); } } }); tasks.Add(task); } Task.WaitAll(tasks.ToArray()); transaction.Commit(); return new Result(Enums.ResultStatus.Success); } } catch(Exception exception) { return new Result(Enums.ResultStatus.Failure, exception.Message + Environment.NewLine + exception.StackTrace); } }
排查方向
- 实体跟踪问题:任务中使用的
product是context1查询出的跟踪实体,context2并未附加该实体,导致SaveChanges()无更新操作。需在context2中重新查询产品,或调用context2.ArtikelTable.Attach(product)并标记实体为修改状态(如context2.Entry(product).State = EntityState.Modified;)。 - 异步操作未等待:调用
ExecuteSqlRawAsync时未加await,会导致存储过程还未执行就执行SaveChanges(),甚至任务结束后操作才完成。必须添加await等待异步调用完成。 - 上下文与连接的状态问题:创建
context2时,需确保共享的数据库连接处于打开状态。可在context1启动事务前手动打开连接:await context1.Database.OpenConnectionAsync();。 - 事务共享有效性:检查
context2.Database.UseTransaction(transaction.GetDbTransaction())是否正确绑定了事务,确认事务对象未失效,且上下文的数据库提供程序与事务匹配。 UpdateArtikel方法逻辑:验证该方法是否正确修改了product的目标字段。若字段未被实际修改,即使上下文跟踪实体,也不会生成更新语句。可通过断点或日志查看修改后的实体字段值。_Context的错误使用:任务中使用外部的_Context调用存储过程,未使用当前任务的context2,导致变更日志操作不在共享事务内,甚至引发多线程访问上下文的问题。需替换为context2.Database.ExecuteSqlRawAsync(...)。- 异常吞入问题:
Task.Run内的异常可能未被外层try-catch捕获,导致隐性失败。建议将Task.WaitAll替换为await Task.WhenAll(tasks)(外层方法为async,应使用异步等待而非阻塞),并在任务内部添加try-catch捕获异常。
内容的提问来源于stack exchange,提问作者dns_nx
相关产品推荐
相关产品推荐

