繁体   English   中英

InvalidOperationException:无法跟踪实体类型'ApplicationUser'的实例

[英]InvalidOperationException: The instance of entity type 'ApplicationUser' cannot be tracked

完整的错误消息:

InvalidOperationException:无法跟踪实体类型'ApplicationUser'的实例,因为已经跟踪了另一个具有相同'{'Id'}键值的实例。 附加现有实体时,请确保仅附加一个具有给定键值的实体实例。 考虑使用'DbContextOptionsBuilder.EnableSensitiveDataLogging'来查看冲突的键值。

当我尝试在“查看”页面上更新用户信息时收到此错误。

更新的代码:

  [HttpGet]
    public ActionResult Edit(string id)
    {
        //Get user and return the Edit View
        ApplicationViewModel model = db.Users.Where(u => u.Id == id)
      .Select(u => new ApplicationViewModel()
      {             
          UserName = u.UserName,
          ClearTextPassword = u.ClearTextPassword,            
          PhoneNumber = u.PhoneNumber,             
          Enabled = u.Enabled

            // Add the remainder properties
        }).FirstOrDefault();
        return View(model);
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(string id, ApplicationViewModel model)
    {
        if (ModelState.IsValid)
            return View(model);

        var user = await _userManager.FindByIdAsync(id);
        if (user == null)
            return NotFound();

        user.UserName = model.UserName;
        user.ClearTextPassword = model.ClearTextPassword;
        user.Enabled = model.Enabled;
        user.PhoneNumber = model.PhoneNumber;

        {
            var result = await _userManager.UpdateAsync(user);
            if (result.Succeeded)
            {
                //db.Entry(listdata).State = EntityState.Modified;
                //db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
        return View(user);
    }

我希望用户信息保存到数据库,并在单击“保存”按钮后在主页上显示更改。

并且,这就是为什么您应该使用视图模型的原因。 除了这一特定例外,实际上还有其他原因。

首先,说明正在发生的事情。 在代码库中的某个位置,在处理此请求期间,查询了一个ID与您尝试编辑的ID相同的ApplicationUser实例。 这可能是由许多不同的原因造成的:重要的部分是您的上下文已经在跟踪此特定实例。

当您在操作中将帖子直接绑定到ApplicationUser ,您将创建一个完全不同的实例。 将该新实例直接添加到您的上下文中,尝试也开始跟踪该实例,但由于与您的上下文已跟踪的内容存在冲突而失败。

两个要点:

  1. 编辑实体时,请始终从数据库中重新提取它,并根据需要对其进行更改,然后将该实例保存回数据库中。

  2. 您绝对不要将帖子中创建的任何内容(即,此处操作的user参数)直接保存到数据库中。 出于很多原因,您不应该这样做,但是安全是第一位的。 发布数据是来自用户的数据,从不信任用户。

使用视图模型可以解决这两个问题。 您只需创建一个像ApplicationUserViewModel这样的类(名称无关紧要),然后向该类中添加用于您要允许用户修改的数据的属性。 换句话说,您将排除诸如ID(ID应该总是来自URL),创建日期和其他审核跟踪之类的东西之类的东西。然后,将帖子绑定到此视图模型,拉出您想要的实际实体从数据库进行修改,将相关数据映射到该实体,然后保存该实体。

总共添加,这将使您的操作类似于:

[HttpPost("{id}"]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, ApplicationUserViewModel model)
{            
    if (!ModelState.IsValid)
        return View(model);

    var user = await _userManager.FindByIdAsync(id);
    if (user == null)
        return NotFound();

    user.FirstName = model.FirstName;
    user.LastName = model.LastName;
    // etc. You can also use a mapping library like AutoMapper instead

    var result = await _userManager.UpdateAsync(user);
    if (result.Succeeded)
    {
        // db.Entry(listdata).State = EntityState.Modified;
        // db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(model);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM