IdentityDbContext.SaveChanges在Claims.Remove或Claims.Clear之后失败

本文关键字:Claims Clear 之后 失败 Remove SaveChanges IdentityDbContext | 更新日期: 2023-09-27 18:21:41

我直接使用AspNetUserClaims表,因为它主要属于我的ASP.NET应用程序,但也从Windows应用程序中使用。ASP.NET应用程序使用Google进行外部登录,而Windows应用程序定期轮询Google帐户并不时刷新访问令牌。因此,现在我在Windows应用程序下工作。

在尝试从AspNetUserClaims表中删除声明时,我遇到了一个异常。它一直告诉我"UserId字段是必需的。"

如果我禁用dc验证。Configuration.ValidateOnSaveEnabled=false,我看到它试图执行UPDATE查询(将所有值传递为NULL或默认值),而不是DELETE。无论我试图删除哪一个特定的声明,即使我使用Clear方法删除了所有声明,它都会失败。

代码还显示了所有用户当前可用的所有声明(这就是为什么有foreach而不是dc.users.Where),但出于调试目的,我删除了这些部分。

var dc = new IdentityDbContext();
foreach (var u in dc.Users.ToList())
{
    if (u.Email == "something@gmail.com")
    {
        u.Claims.Clear();
    }
}
dc.SaveChanges();

这只涉及删除索赔。我成功地使用claims添加了新索赔。通过更改Claim.ClaimValue添加或更新现有索赔的值。原因可能是什么?

事实上,我可以不删除声明,因为我的Windows应用程序只需要更新声明(使用刷新令牌更新访问令牌)。但我很好奇为什么删除不起作用。

好吧,我找到了一种删除令牌的方法,代码是:

var dc = new IdentityDbContext();
var manager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(dc));
var user = manager.FindByEmail("something@gmail.com");
Claim c = manager.GetClaims(user.Id).Where(c => c.Type == "GoogleAccessToken").FirstOrDefault();
if (c != null)
{
    manager.RemoveClaim(user.Id, c);
}

但仍然不清楚为什么不使用UserManager的原始代码不能删除声明。

IdentityDbContext.SaveChanges在Claims.Remove或Claims.Clear之后失败

这些都是实体框架的怪癖
当你说

user.Claims.Remove(claim);
dbContext.SaveChanges();

这只会将声明对象的外键重置为null,但这是不允许的。EF对此一无所知,因此没有DELETE语句。

如果您想删除EF中的对象,请执行以下操作:

dbContext.UserClaims.Remove(claim);

但是您需要将IDbSet<UserClaim> UserClaims映射到dbContext,因为默认情况下它不可用。

阅读本文

中有关EF删除对象方法的更多信息