【问题标题】:EF Core - no database update on SaveChangesEF Core - SaveChanges 上没有数据库更新
【发布时间】: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


【解决方案1】:

你可以让你的代码更简单:

public async Task<bool> UpdateUserDataByAsync(UserModel updatedUser, ClaimsPrincipal currentUser)
        {
 UserDbContext.Entry(updatedUser).State = EntityState.Modified;
 return await UserDbContext.SaveChangesByAsync(currentUser) > 0;
}

【讨论】:

  • 谢谢。那么UserDbContext.Entry(updatedUser) 将如何找到需要更新的正确用户?它是否通过 Id 检查?
  • 是的,它使用泛型重载函数来查找对象的类型和 ID。仅当您的实体具有主键时,它才能正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多