使用 UserManager 的 UpdateAsync 方法会在 EntityFrameworkCore 上抛出 InvalidOperationException

问题描述 投票:0回答:1

我正在将 dotnet Framework 项目更新为 dotnet Core。我有一个

UserProfileService
类来处理所有用户。它有一个
UserManager
,它是使用 dotnet 核心依赖注入来注入的。

当我尝试更新

UserProfile
(这是从
IdentityUser
派生的类)时,会抛出以下
InvalidOperationException
错误:

The instance of entity type 'UserProfile' cannot be tracked because another instance with the key value '{Id: GUID}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

使用

dbContext
中的以下代码连接
Startup.cs

services.AddIdentityCore<UserProfile>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddEntityFrameworkStores<AvgContext>()
.AddDefaultTokenProviders();

在此调用之前我没有从上下文中获取该用户,因此这种情况似乎不太可能发生。

有人知道会发生什么情况吗?

c# .net-core entity-framework-core invalidoperationexception usermanager
1个回答
0
投票

在此调用之前我没有从上下文中获取此用户

直接,也许不是。间接地,这仍然很重要。如果您使用 DbContext 加载用户实体,则应始终在使用

Update
Attach
之前验证是否跟踪实体:

var trackedUser = _dbContext.Users.Local.FirstOrDefault(x => x.UserId == userId);

如果 trackedUser 返回一个值,您应该将数据复制到其中并调用 SaveChanges,否则您可以考虑附加或使用

Update
,尽管我通常建议始终在更新场景中加载实体,因为这断言实体存在,并且您可以在应用可能过时的更新之前检查任何当前的并发标志(即 RowVersion/Timestamp)。

作为一个简单的规则,请避免使用

Update
/
UpdateAsync
。使用 DbContext 时。 UserManager 提供了一些 EF 的包装器,但仍然旨在复制值。

var user = await UserManager.FindByIdAsync(userId);
// Copy values across based on what is allowed to be updated.
user.Email = dto.Email; // etc.
await UserManager.UpdateAsync(user);

如果您直接使用 DbContext 来访问 User 实体:

var user = await _dbContext.Users.SingleAsync(x => x.UserId == userId);
// copy values across based on what is allowed to be updated.
user.Email = dto.Email; // etc.
await _dbContext.SaveChangesAsync();
© www.soinside.com 2019 - 2024. All rights reserved.