【发布时间】:2021-02-26 12:15:57
【问题描述】:
今天我有点惊讶我的 DbContext 的 SaveChanges() 方法没有按预期工作。
这是我用来从 Db 获取用户数据的方法:
public async Task<UserModel> GetUserByIdAsync(string Id, bool editMode)
{
if (editMode) return await UserDbContext.Users.FirstOrDefaultAsync(usr => usr.UserId == Id);
else return await UserDbContext.Users.AsNoTracking().FirstOrDefaultAsync(usr => usr.UserId == Id);
}
这是应该在 Db 中更新实体的方法:
public async Task<bool> UpdateUserDataByAsync(UserModel updatedUser, ClaimsPrincipal currentUser)
{
var user = await GetUserByIdAsync(updatedUser.UserId, true);
user = updatedUser;
return await UserDbContext.SaveChangesByAsync(currentUser) > 0;
}
另外,SaveChangesByAsync 方法只是被覆盖 SaveChanges() 以自动更新一些 Db 列,例如 UpdatedBy:
public async Task<int> SaveChangesByAsync(ClaimsPrincipal userPrincipal,
CancellationToken cancellationToken = new CancellationToken())
{
try
{
DateTime now = DateTime.UtcNow;
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is BaseModel && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
((BaseModel)entityEntry.Entity).UpdatedDate = now;
((BaseModel)entityEntry.Entity).UpdatedBy = userPrincipal.FindFirstValue("UserId") ?? "Anonymous";
if (entityEntry.State == EntityState.Added)
{
((BaseModel)entityEntry.Entity).CreatedDate = now;
((BaseModel)entityEntry.Entity).CreatedBy = userPrincipal.FindFirstValue("UserId") ?? "Anonymous";
}
}
return await base.SaveChangesAsync(cancellationToken);
}
catch (TaskCanceledException)
{
return await Task.FromCanceled<int>(cancellationToken);
}
}
最终我通过将UpdateUserDataByAsync更改为以下内容克服了这个问题:
UserDbContext.Entry(await GetUserByIdAsync(updatedUser.UserId, true)).CurrentValues.SetValues(updatedUser);
return await UserDbContext.SaveChangesByAsync(currentUser) > 0;
但是我想问你为什么初始版本不起作用?由于用户在没有AsNoTracking() 修饰符的情况下被拉出,上下文不应该继续跟踪任何变化吗,在这种情况下是用updatedUser 数据简单地替换user 数据?
谢谢!
【问题讨论】:
-
user = updatedUser;会覆盖引用,但不会触发更改跟踪。 -
@HenkHolterman,谢谢!那么这种方法是否只有在我知道哪些属性已更改以避免直接手动更新用户时才有用?在所有其他情况下我应该选择
CurrentValues.SetValues吗?
标签: c# sql-server .net-core entity-framework-core blazor