多关联表更新时部分数据库实例触发DbUpdateConcurrencyException求助
我在应用里尝试通过一次API调用更新多层关联表:
Topic | 1:1 | TopicDetails | 1:n | TopicSections
子表部分条目初始不存在,需要首次使用时创建而非更新。这个逻辑在部分数据库实例上正常,但在其他实例中抛出了并发异常。想请教:是否必须先新增条目再更新,还是有办法通过一次调用同时处理新增和更新操作?
服务处理代码
public async Task<ServiceResponse<Topic>> UpdateTopicDetails(UpdateTopicDetailsRequestDto request, string token) { var serviceResponse = new ServiceResponse<Topic>() { }; Topic? topicFromDb = await _db.Topics.FirstOrDefaultAsync(t => t.TopicId == request.TopicId); TopicDetails? topicDetails = topicFromDb?.Details; Researcher researcherFromToken = await GetResearcherFromToken(token); if (researcherFromToken == null || topicFromDb == null) { serviceResponse.Data = topicFromDb; serviceResponse.Messages = new List<string>() { "Unauthorized 1" }; return serviceResponse; } if (topicDetails != null && topicDetails?.ResearcherId != researcherFromToken.ResearcherId) { serviceResponse.Messages = new List<string>() { "Unauthorized 2" }; return serviceResponse; } List<TopicSection> sections = new() { }; foreach(TopicSection section in request.Sections) { TopicSection sectionToAdd = new() { SectionId = section.SectionId, SectionTitle = section.SectionTitle, SectionBody = section.SectionBody, }; sections.Add(section); } TopicDetails topicDetailsToAdd = new() { ResearcherId = researcherFromToken.ResearcherId, Researcher = researcherFromToken, Sections = sections, }; if (request.TopicDetailsId != null) topicDetailsToAdd.TopicDetailsId = (int)request.TopicDetailsId; topicFromDb.Details = topicDetailsToAdd; _db.Topics.Update(topicFromDb); bool success = _db.SaveChanges() > 0; if (!success) { serviceResponse.Messages = new List<string>() { "Failure " }; return serviceResponse; } serviceResponse.Data = topicFromDb; serviceResponse.Success = true; return serviceResponse; }
报错信息
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded.
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(RelationalDataReader reader, Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithRowsAffectedOnly(Int32 commandIndex, RelationalDataReader reader)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList1 entries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList1 entriesToSave) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<>c.<SaveChanges>b__107_0(DbContext _, ValueTuple2 t)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at SdeResearch.Api.Services.TopicService.TopicService.UpdateTopicDetails(UpdateTopicDetailsRequestDto request, String token) in C:\Users\UserName\source\repos\SdeResearch\SdeResearch.Api\Services\TopicService\TopicService.cs:line 67
at SdeResearch.Api.Controllers.TopicController.UpdateTopicDetailsAsync(UpdateTopicDetailsRequestDto request, String Authorization) in C:\Users\UserName\source\repos\SdeResearch\SdeResearch.Api\Controllers\TopicController.cs:line 125
at lambda_method85(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
若需要查看调用接口的React组件、JWT令牌验证方法或其他信息,请告知。
内容的提问来源于stack exchange,提问作者Morgan Bradford

