我有以下问题。使用以下代码更改用户的当前角色时,我会收到如下消息的异常:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult Edit(User user, string role)
{
if (ModelState.IsValid)
{
var oldUser = DB.Users.SingleOrDefault(u => u.Id == user.Id);
var oldRoleId = oldUser.Roles.SingleOrDefault().RoleId;
var oldRoleName = DB.Roles.SingleOrDefault(r => r.Id == oldRoleId).Name;
if (oldRoleName != role)
{
Manager.RemoveFromRole(user.Id, oldRoleName);
Manager.AddToRole(user.Id, role);
}
DB.Entry(user).State = EntityState.Modified;
return RedirectToAction(MVC.User.Index());
}
return View(user);
}
附加类型为' Models.Entities.User'的实体失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。
有人知道解决这个问题的好方法吗?
答案 0 :(得分:11)
问题是您的Manager和DB不使用相同的DbContext。因此,当您将用户从数据库上下文发送到Manager时,它会将其作为“新”用户处理 - 然后您无法将其从角色中删除。你有两种方式去这里。最简单的方法是从管理员处获取用户。
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult Edit(User user, string role)
{
if (ModelState.IsValid)
{
// THIS LINE IS IMPORTANT
var oldUser = Manager.FindById(user.Id);
var oldRoleId = oldUser.Roles.SingleOrDefault().RoleId;
var oldRoleName = DB.Roles.SingleOrDefault(r => r.Id == oldRoleId).Name;
if (oldRoleName != role)
{
Manager.RemoveFromRole(user.Id, oldRoleName);
Manager.AddToRole(user.Id, role);
}
DB.Entry(user).State = EntityState.Modified;
return RedirectToAction(MVC.User.Index());
}
return View(user);
}
更优雅的方式是开始使用像AutoFac(https://code.google.com/p/autofac/wiki/MvcIntegration)这样的DI框架,并将你的DbContext设置为InstancePerApiRequest。
builder.RegisterType<YourDbContext>().As<DbContext>().InstancePerApiRequest();
答案 1 :(得分:0)
我的角色是在我的DbMigrationsConfiguration类的种子方法中管理的,我将其重命名为:
if (context.Roles.Any(r => r.Name == "User"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = manager.Roles.First(r => r.Name == "User");
role.Name = "NewNameForUser";
manager.Update(role);
}