为啥我不能用 Attach() 更新 IdentityUser?

Posted

技术标签:

【中文标题】为啥我不能用 Attach() 更新 IdentityUser?【英文标题】:Why can't I update IdentityUser with Attach()?为什么我不能用 Attach() 更新 IdentityUser? 【发布时间】:2021-07-01 07:28:09 【问题描述】:

下面的代码抛出:

数据库操作预计会影响 1 行,但实际上影响了 0 行。

var updatedUser = new User  Id = _currentUserService.UserId, MyBool = true ;
_dbContext.Users.Attach(updatedUser);
_dbContext.Entry(updatedUser).Property(user => user.MyBool).IsModified = true;
await _dbContext.SaveChangesAsync()

用户是从IdentityUser 继承的,这是我项目中唯一一个这种更新方法不起作用的地方。我在没有UserManager 的情况下这样做,因为我不想获取所有用户列。我想要的只是更新MyBool 属性。所以我不需要其他方法来做到这一点,我只是想了解我为什么会出现这种行为。

当然,我传递的不是同一个布尔值。 我假设我不明白IdentityUserDbContext 的影响,因为上面的代码适用于我所有未与Identity 连接的自定义实体。

【问题讨论】:

欢迎来到 Stack Overflow。请通过tour 了解 Stack Overflow 的工作原理,并阅读How to Ask 以了解如何提高问题的质量。然后edit你的问题包含你拥有的完整源代码作为minimal reproducible example,其他人可以编译和测试。 我忘了在我的问题中添加 await _dbContext.SaveChangesAsync(),我的错。如果我没有在我的项目中编写它,我不会得到预期会影响 1 行但实际上影响 0 行异常的数据库操作。这个问题仍然相关.. 如果你想执行UPDATE SET MyBool=1 Where ID=@id,就这样做。不要试图通过 ORM 来近似它。所有 ORM 都是为处理对象图而构建的,而不是作为 SQL 的替代品。要使用 ORM 更新对象,您必须加载对象、修改它然后持久化它。是的,这很慢,需要两次往返,而且更有可能导致并发冲突。 是的,我已经被告知无论我要更新多少列,我都应该获取整个实体。是的,正如你提到的,我害怕性能速度。看起来我正在尝试结合 SQL 和 ORM 的最佳效果,并有点破坏 ORM 的概念。 【参考方案1】:

IdentityDbContext<TUser> 的基类中,您可以在 OnModelCreating() 中找到以下内容:

b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();

所以你的var updatedUser = new User 方法不起作用。

您需要先获取用户。在无论如何都应该如此的普通代码中,您不想在“更新”中丢失名称和其他所有内容,对吗?

【讨论】:

只修改一个属性而不覆盖任何其他属性是一种非常好的方法。但是您正确地指出他们还应该设置确实需要往返数据库的 ConcurrencyStamp 属性。 是的,我知道。我用 IsModified 误读了该行。当您进行往返时,您不妨将其留给 ChangeTracker。 哦,谢谢你的回答,我稍后再看看。【参考方案2】:

我总是使用这样的代码:

var existedUser = _dbContext.Set<ApplicationUser>()
                            .FirstOrDefault( i=> i.UserId=_currentUserService.UserId);

if(existedUser ==null) ... error

existedUser.MyBool=true;
_dbContext.Entry(existedUser).Property(user => user.MyBool).IsModified = true;
await _dbContext.SaveChangesAsync();
    

【讨论】:

我不想获取所有用户列。这就是问题的重点。请参阅另一个答案:它要求从数据库中检索 ConcurrencyStamp 的当前值。不获取整个记录是否只是过早优化是另一个讨论。

以上是关于为啥我不能用 Attach() 更新 IdentityUser?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能用我的 api 响应更新我的状态?数据是一个对象数组

如何从 Twitter 更新 Identi.ca

C# 为啥更新功能在普通button可以,在toolStripButton就不能实现功能呢?

locate命令为啥不能用

为啥我不能更新 laravel 中的字段?

Vue数组更新,为啥不能通过索引直接设置一个值