InvalidOperationException: экземпляр типа объекта «ApplicationUser» не может быть отслежен - PullRequest
0 голосов
/ 02 июля 2019

Полное сообщение об ошибке:

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);
    }

Я ожидаю, что информация о пользователе сохранится в базе данных и отобразит изменения на домашней странице после нажатия кнопки Сохранить.

1 Ответ

0 голосов
/ 02 июля 2019

И вот почему вы должны использовать модели представления. На самом деле есть и другие причины, кроме одного конкретного исключения.

Во-первых, объяснение того, что происходит. Где-то в вашей кодовой базе во время обработки этого запроса был запрошен экземпляр ApplicationUser с тем же идентификатором, что и у того, что вы пытаетесь редактировать. Это могло быть вызвано множеством разных вещей: важная часть заключается в том, что ваш контекст уже отслеживает этот конкретный экземпляр.

Когда вы прямо в своем действии связываете пост с ApplicationUser, вы создаете совершенно другой экземпляр. Добавление этого нового экземпляра непосредственно в ваш контекст, попытка начать отслеживание этого экземпляра также завершается неудачно, поскольку существует конфликт с тем, что уже отслеживает ваш контекст.

Два выноса:

  1. При редактировании объекта ВСЕГДА извлекайте его из базы данных, изменяйте его по мере необходимости, а затем сохраняйте этот экземпляр обратно в базу данных.

  2. Вы НИКОГДА не должны напрямую сохранять что-либо, созданное из сообщения (т. Е. user параметр вашего действия здесь), в вашу базу данных. Есть целый ряд причин, почему вы не должны этого делать, но безопасность - это в первую очередь. Данные публикации - это данные пользователя, и НИКОГДА не доверяйте пользователю.

Использование модели представления устраняет обе эти проблемы. Вы просто создаете класс, такой как ApplicationUserViewModel (имя не имеет значения), а затем добавляете свойства к этому only для данных, которые вы хотите разрешить пользователю изменять. Другими словами, вы исключили бы такие вещи, как идентификатор (идентификаторы должны ВСЕГДА поступать из 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...