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