如何处理 IdentityUser 更新的并发失败?
Posted
技术标签:
【中文标题】如何处理 IdentityUser 更新的并发失败?【英文标题】:How to deal with concurrency failure on IdentityUser update? 【发布时间】:2019-03-04 08:53:44 【问题描述】:我有一种方法可以在我们的应用中更新用户声明。
我以管理员用户身份登录,可以编辑其他用户。
我正在尝试删除一位用户的现有声明并分配新的声明。
使用UserManger
删除声明时,我得到ConcurrencyFailure
结果。 (有时它可以工作,但大多数时候它会返回失败错误。)
代码:“并发失败”
描述:“乐观并发失败,对象已被修改。”
方法:
public async Task<bool> AssignClaimsToUser(string id, List<string> newClaims)
bool success = false;
ApplicationUser user = await _userManager.FindByIdAsync(id);
List<Claim> userClaims = new List<Claim>();
// Remove existing claims
IList<Claim> existingClaims = await _userManager.GetClaimsAsync(user);
var removal = await _userManager.RemoveClaimsAsync(user, existingClaims); // This fail
if (removal.Succeeded)
success = true;
// Add new claims
foreach (string policy in newClaims)
userClaims.Add(new Claim(policy, string.Empty, ClaimValueTypes.String));
await _userManager.AddClaimsAsync(user, userClaims);
return success;
为什么会发生这种情况以及如何解决这个问题?
我只有在删除声明时才会遇到这个问题。在IdentityUser
上调用其他方法时我没有。
编辑
调试输出:
Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求 开始 HTTP/1.1 POST http://localhost:47691/Users/ManageUsers_Update 应用程序/x-www-form-urlencoded;字符集=UTF-8 246 Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:信息: HttpContext.User 通过 AutomaticAuthentication 从 身份验证方案:Identity.Application。 Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息: 用户授权成功:user@mydomain.com。 Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息: 用户授权成功:user@mydomain.com。 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息: 执行动作方法 MyProject.Controllers.UsersController.ManageUsers_Update (MyProject) 带参数(Kendo.Mvc.UI.DataSourceRequest, MyProject.Views.ViewModels.ManageUsersViewModel) - ModelState 是有效的 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__id_0='?' (大小 = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__custRef_0='?' (大小 = 10)], CommandType='Text', CommandTimeout='30'] 选择顶部 (1) [c].[CustomerDetailsId], [c].[CustRef], [c].[CustomerDBConnectionString], [c].[Enabled], [c].[Name], [c].[UserLicenses] FROM [CustomerDetails] AS [c] WHERE [c].[CustRef] = @__custRef_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__custRef_0='?' (大小 = 10)], CommandType='Text', CommandTimeout='30'] SELECT [x].[ID], [x].[AspNetUserId], [x].[CustRef], [x].[CustomerId], [x].[Email], [x].[FirstName], [x].[IsEnabled], [x].[IsMaster], [x].[ShowCosts], [x].[Surname] FROM [Users] AS [x] WHERE [x].[CustRef] = @__custRef_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__users_Id_0='?'], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [a].[ID], [a].[AspNetUserId]、[a].[CustRef]、[a].[CustomerId]、[a].[Email]、 [a].[FirstName], [a].[IsEnabled], [a].[IsMaster], [a].[ShowCosts], [a].[Surname] FROM [Users] AS [a] WHERE [a].[ID] = @__users_Id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__id_0='?' (大小 = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__normalizedUserName_0='?' (大小 = 256)],CommandType='Text',CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[NormalizedUserName] = @__normalizedUserName_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (6ms) [Parameters=[@p16='?' (大小 = 450), @p0='?', @p1='?' (大小 = 4000),@p17='?' (大小 = 4000),@p2='?' (大小 = 4000), @p3='?' (大小 = 256)、@p4='?'、@p5='?'、@p6='?'、@p7='?'、@p8='?' (大小 = 256),@p9='?' (大小 = 256),@p10='?' (大小 = 4000),@p11='?' (大小 = 4000),@p12='?',@p13='?' (大小 = 4000),@p14='?',@p15='?' (大小 = 256)],CommandType='Text',CommandTimeout='30'] SET NOCOUNT 在;更新 [AspNetUsers] 设置 [AccessFailedCount] = @p0, [ConcurrencyStamp] = @p1,[CustRef] = @p2,[电子邮件] = @p3, [EmailConfirmed] = @p4,[IsEnabled] = @p5,[LockoutEnabled] = @p6, [LockoutEnd] = @p7,[NormalizedEmail] = @p8,[NormalizedUserName] = @p9,[密码哈希] = @p10,[电话号码] = @p11, [PhoneNumberConfirmed] = @p12,[SecurityStamp] = @p13, [TwoFactorEnabled] = @p14,[用户名] = @p15 其中 [Id] = @p16 和 [并发标记] = @p17;选择@@行计数; Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__menuId_0='?'], CommandType='Text',CommandTimeout='30'] SELECT [u].[CustomerMenuId], [u].[MenuItemId] FROM [CustomerMenuItem] AS [u] WHERE [u].[CustomerMenuId] = @__menuId_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT [m].[Id], [m].[AspNetPolicyId], [m].[GlyphIcon], [m].[Label], [m].[MenuGroupId] FROM [MenuItem] AS [m] Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] 选择 [a].[Id], [a].[DefaultAction], [a].[Description], [a].[Name] FROM [AspNetPolicy] AS [a] Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__id_0='?' (大小 = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__user_Id_0='?' (大小 = 450)], CommandType='Text', CommandTimeout='30'] SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE [uc].[UserId] = @__user_Id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (9ms) [Parameters=[@__8__locals1_user_Id_0='?' (大小 = 450),@__claim_Value_1='?' (大小 = 4000),@__claim_Type_2='?' (大小 = 4000)],CommandType='Text',CommandTimeout='30'] 选择 [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (6ms) [Parameters=[@__8__locals1_user_Id_0='?' (大小 = 450),@__claim_Value_1='?' (大小 = 4000),@__claim_Type_2='?' (大小 = 4000)],CommandType='Text',CommandTimeout='30'] 选择 [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (93ms) [Parameters=[@__8__locals1_user_Id_0='?' (大小 = 450),@__claim_Value_1='?' (大小 = 4000),@__claim_Type_2='?' (大小 = 4000)],CommandType='Text',CommandTimeout='30'] 选择 [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (5ms) [Parameters=[@__normalizedUserName_0='?' (大小 = 256)],CommandType='Text',CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[NormalizedUserName] = @__normalizedUserName_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (6ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p19='?' (大小 = 450),@p3='?',@p4='?' (大小 = 4000),@p20='?' (尺寸 = 4000), @p5='?' (大小 = 4000),@p6='?' (大小 = 256)、@p7='?'、@p8='?'、@p9='?'、@p10='?'、@p11='?' (大小 = 256),@p12='?' (大小 = 256), @p13='?' (大小 = 4000),@p14='?' (大小 = 4000), @p15='?', @p16='?' (大小 = 4000),@p17='?',@p18='?' (大小 = 256)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON;删除自 [AspNetUserClaims] 在哪里 [Id] = @p0;选择@@行计数;删除自 [AspNetUserClaims] 在哪里 [Id] = @p1;选择@@行计数;删除自 [AspNetUserClaims] 在哪里 [Id] = @p2;选择@@行计数;更新 [AspNetUsers] SET [AccessFailedCount] = @p3,[ConcurrencyStamp] = @p4, [CustRef] = @p5,[电子邮件] = @p6,[EmailConfirmed] = @p7,[IsEnabled] = @p8,[LockoutEnabled] = @p9,[LockoutEnd] = @p10,[NormalizedEmail] = @p11,[NormalizedUserName] = @p12,[PasswordHash] = @p13, [PhoneNumber] = @p14,[PhoneNumberConfirmed] = @p15,[SecurityStamp] = @p16,[TwoFactorEnabled] = @p17,[用户名] = @p18 其中 [Id] = @p19 AND [ConcurrencyStamp] = @p20;选择@@行计数; 'dotnet.exe' (CoreCLR:clrhost):已加载 'C:\Users\jsmith.nuget\packages\system.diagnostics.stacktrace\4.3.0\lib\netstandard1.3\System.Diagnostics.StackTrace.dll'。 跳过加载符号。模块经过优化和调试器选项 “只是我的代码”已启用。 Microsoft.EntityFrameworkCore.DbContext:错误:发生异常 在数据库中保存更改。 Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库 操作预计会影响 1 行,但实际上影响了 0 行。 自加载实体以来,数据可能已被修改或删除。看 http://go.microsoft.com/fwlink/?LinkId=527962 获取有关信息 理解和处理乐观并发异常。在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex,Int32 预期行影响,Int32 行影响)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__2.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.d__1.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__47.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__45.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.DbContext.d__30.MoveNext()
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库 操作预计会影响 1 行,但实际上影响了 0 行。 自加载实体以来,数据可能已被修改或删除。看 http://go.microsoft.com/fwlink/?LinkId=527962 获取有关信息 理解和处理乐观并发异常。在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex,Int32 预期行影响,Int32 行影响)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__2.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.d__1.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__47.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__45.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.EntityFrameworkCore.DbContext.d__30.MoveNext() Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:信息: 执行 DbCommand (6ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p19='?' (大小 = 450),@p3='?',@p4='?' (大小 = 4000),@p20='?' (尺寸 = 4000), @p5='?' (大小 = 4000),@p6='?' (大小 = 256)、@p7='?'、@p8='?'、@p9='?'、@p10='?'、@p11='?' (大小 = 256),@p12='?' (大小 = 256), @p13='?' (大小 = 4000),@p14='?' (大小 = 4000), @p15='?', @p16='?' (大小 = 4000),@p17='?',@p18='?' (大小 = 256)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON;删除自 [AspNetUserClaims] 在哪里 [Id] = @p0;选择@@行计数;删除自 [AspNetUserClaims] 在哪里 [Id] = @p1;选择@@行计数;删除自 [AspNetUserClaims] 在哪里 [Id] = @p2;选择@@行计数;更新 [AspNetUsers] SET [AccessFailedCount] = @p3,[ConcurrencyStamp] = @p4, [CustRef] = @p5,[电子邮件] = @p6,[EmailConfirmed] = @p7,[IsEnabled] = @p8,[LockoutEnabled] = @p9,[LockoutEnd] = @p10,[NormalizedEmail] = @p11,[NormalizedUserName] = @p12,[PasswordHash] = @p13, [PhoneNumber] = @p14,[PhoneNumberConfirmed] = @p15,[SecurityStamp] = @p16,[TwoFactorEnabled] = @p17,[用户名] = @p18 其中 [Id] = @p19 AND [ConcurrencyStamp] = @p20;选择@@行计数; Microsoft.EntityFrameworkCore.DbContext:错误:发生异常 在数据库中保存更改。 Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库 操作预计会影响 1 行,但实际上影响了 0 行。 自加载实体以来,数据可能已被修改或删除。看 http://go.microsoft.com/fwlink/?LinkId=527962 获取有关信息 理解和处理乐观并发异常。在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex,Int32 预期行影响,Int32 行影响)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagation(Int32 commandIndex,DbDataReader 阅读器)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(DbDataReader 读者)在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection 连接)在 Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable
1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList
1 条目保存)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(布尔 接受AllChangesOnSuccess)在 Microsoft.EntityFrameworkCore.DbContext.SaveChanges(布尔值 接受AllChangesOnSuccess)Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库 操作预计会影响 1 行,但实际上影响了 0 行。 自加载实体以来,数据可能已被修改或删除。看 http://go.microsoft.com/fwlink/?LinkId=527962 获取有关信息 理解和处理乐观并发异常。在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex,Int32 预期行影响,Int32 行影响)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagation(Int32 commandIndex,DbDataReader 阅读器)在 Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(DbDataReader 读者)在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection 连接)在 Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable
1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList
1 条目保存)在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(布尔 接受AllChangesOnSuccess)在 Microsoft.EntityFrameworkCore.DbContext.SaveChanges(布尔值 acceptAllChangesOnSuccess) 抛出异常: 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException' 在 Microsoft.EntityFrameworkCore.dll 线程 0x6264 已退出 代码 0 (0x0)。线程 0xaa0 以代码 0 (0x0) 退出。这 线程 0x6a84 以代码 0 (0x0) 退出。
ManageUsers_Update:
public async Task<ActionResult> ManageUsers_Update([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel viewModel)
if (viewModel != null && ModelState.IsValid)
User objToUpdate = new User
Id = viewModel.ID,
FirstName = viewModel.FirstName,
Surname = viewModel.Surname
;
_userRepository.UpdateUser(objToUpdate);
if (viewModel.CustomerMenuId != null && viewModel.CustomerMenuId > 0)
int customerMenuId = Convert.ToInt32(viewModel.CustomerMenuId);
// Update user's claims
List<string> newClaims = _navigationRepository.GetPolicyNamesByCustomerMenuId(customerMenuId);
bool claimsUpdated = await _applicationUserService.AssignClaimsToUser(viewModel.AspNetUserId, newClaims);
// Assign user to menu if updating claims succeeded
if (claimsUpdated)
_navigationRepository.AssignCustomerMenuToUser(new CustomerMenuUser()
CustomerMenuId = customerMenuId, AspNetUserId = viewModel.AspNetUserId);
ApplicationUser user = await _userManager.FindByIdAsync(viewModel.AspNetUserId);
user.IsEnabled = viewModel.IsEnabled;
await _userManager.UpdateAsync(user);
return Json(new[] viewModel .ToDataSourceResult(request, ModelState));
【问题讨论】:
您能否提供一些有关您的环境和框架版本的详细信息? Microsoft.AspNetCore.Identity.EntityFrameworkCore 1.0.2; .NET 核心 1.1;视窗 10 专业版; Microsoft.EntityFrameworkCore.SqlServer 1.0.3 【参考方案1】:为什么会这样?
最可能的原因是并发冲突,这意味着多个用户(线程)试图更改相同的数据。
您可以在此处找到有关其发生方式的更多详细信息
https://docs.microsoft.com/en-us/ef/core/saving/concurrency
如何解决这个问题?
我假设在您的情况下,多个用户不应该更新相同的声明,因此可能存在请求重复。
你可以试试:
检查数据库中的数据是否更新。如果有多个请求,其中一个应保存更改; 在发布请求时检查浏览器中的“网络”选项卡或设置断点并查看在单个请求期间它被命中了多少次; 从应用程序中分离出有缺陷的代码并尝试重现该问题。另一种方法(通常在允许多重访问时)是实施重试策略以在乐观失败的情况下重新执行更新逻辑。 我很确定这不适合您的情况,但如果您需要快速解决方案,这将起作用。
【讨论】:
多个用户不可能尝试更新同一记录,因为我是唯一使用/处理它的用户。通常第一次更改是成功的,即使我注销并重新登录后,以下尝试也会失败。 1. 成功的移除会按照预期正确更新声明。 2. 请求仅提出一次。 @伊万 @nickornotto 如果您与重现问题的代码共享一个 repo 会很棒 如果需要,我可以分享更多信息,但不能分享项目。还涉及到数据库,而且很大 能否提供调试输出? 我尝试使用您引用的 MS 文章中的捕获,但它无法解决主要问题:删除失败的现有声明。 catch sn-p 只处理EntityEntry
的属性,即ApplicationUser
,这是正确的,不需要更新。只是并发标记正在改变。【参考方案2】:
在我的情况下,我在使用 _roleManager.UpdateAsync
时遇到了同样的错误,我正在发送一个角色模型来更新方法,然后这给了我错误,我认为我收到这个错误是因为检索数据的过程我正在运行以在屏幕中加载数据(FindByIdAsync 以获取声明和其他内容)
执行从角色管理器获取的操作可能会将实体保留在内存中,因为我们使用的是实体框架,所以我所做的只是在更新命令之前使用 _roleManager.FindByIdAsync ,这将为我提供我应该更新的当前实体.
【讨论】:
【参考方案3】:在我的情况下,解决方案很简单: 当我在产品之前删除类别(也从 ProductCategories 中删除数据)时,我有产品、类别和 ProductCategories,我和你一样遇到错误。 问题是他正在尝试删除由于类别已被删除而没有机会存在的关系。
【讨论】:
【参考方案4】:我不确定这是否有帮助,因为它有点不相关,但我在代码“ConcurrencyFailure”(以及描述“乐观并发失败,对象已被修改。”)中遇到了相同的并发错误,如下所示步骤,可能会帮助找到这个问题的人尝试解决与我相同的问题:
我使用自己的单元测试项目创建了一个 .NET Core 5 API
我创建了自己的 Domain.IdentityUser(派生自 IdentityUser)和 Domain.IdentityRole(派生自 IdentityRole,必须设置 NormalizedName 才能让 UserManager
我创建了一个单元测试,创建了一个 UserManager
new UserStore<Domain.IdentityUser, Domain.IdentityRole, ApplicationDbContext, long>(applicationDbContext)
并且UserManager
new Microsoft.Extensions.Logging.Logger<UserManager<Domain.IdentityUser>>(new Microsoft.Extensions.Logging.LoggerFactory())
将 UserManager
商店 UserStore
"Succeeded": false,
"Errors": [
"Code": "ConcurrencyFailure",
"Description": "Optimistic concurrency failure, object has been modified."
]
我不得不在单元测试中到处使用相同的 ApplicationDbContext 实例,同时从内存数据库加载数据,而不是依赖新创建的对象。
【讨论】:
以上是关于如何处理 IdentityUser 更新的并发失败?的主要内容,如果未能解决你的问题,请参考以下文章