У меня есть модель БД, для которой я хотел бы редактировать несколько видов.Моя фактическая модель БД намного больше, чем та, которую я показываю здесь.
Модель БД: PersonModel
public class PersonModel {
public Int32 Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Description { get; set; }
}
У меня есть дваПредставления EditPersonName.cshtml и EditPersonDescription.cshtml , которые позволяют пользователю изменять различные части PersonModel .
Просмотр 1: EditPersonName.cshtml
@model EditPersonNameModel
@using (Html.BeginForm()) {
<div class="editor-label">@Html.LabelFor(m => m.FirstName)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.FirstName)</div>
<div class="editor-label">@Html.LabelFor(m => m.LastName)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.LastName)</div>
<input type="submit" value="Save" />
}
Просмотр 2: EditPersonDescription.cshtml
@model EditPersonDescriptionModel
@using (Html.BeginForm()) {
<div class="editor-label">@Html.LabelFor(m => m.Description)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.Description)</div>
<input type="submit" value="Save" />
}
Вместо того чтобы привязывать каждое представление непосредственно к PersonModel , я хочу связать их с EditPersonNameModel и EditPersonDescriptionModel соответственно.
Просмотреть модель 1: EditPersonNameModel
public class EditPersonNameModel {
public string FirstName { get; set; }
public string LastName { get; set; }
}
Просмотреть модель 2: EditPersonDescriptionModel
public class EditPersonDescriptionModel {
public string Description { get; set; }
}
Полагаю, стоит также упомянуть, что я использую шаблон DbContext EF.
public class PersonDbContext : DbContext {
public DbSet<PersonModel> Persons { get; set; }
}
Теперь для моего контроллера, с которого все и начинаетсяперерыв!
Контроллер: PersonController
public class PersonController {
private PersonDbContext = new PersonDbContext();
[HttpGet]
public ActionResult EditName(int id) {
// ??? ---- #1 -----
}
[HttpPost]
public ActionResult EditName(EditPersonNameModel model, int id) {
if (ModelState.IsValid) {
// ??? ---- #2 ----- ??? Update FirstName,LastName ONLY
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
[HttpGet]
public ActionResult EditDescription(int id) {
// ??? ---- #3 -----
}
[HttpPost]
public ActionResult EditDescription(EditPersonDescriptionModel model, int id) {
if (ModelState.IsValid) {
// ??? ---- #4 ----- ??? Update Description ONLY
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
}
Моя проблема в том, что я не знаю, что поместить в блоки ??? ---- #X -----
выше.Очевидно, что #1
и #3
будут очень похожи, как и #2
и #4
.
Некоторые предложили использовать AutoMapper .Это помогает перейти от модели Db к модели представления, но не наоборот.
В настоящее время мой блок кода для #1
выглядит следующим образом:
[HttpGet]
public ActionResult EditName(int id) {
PersonModel person = db.Persons.Find(id);
if (person == null) {
return HttpNotFound();
}
EditPersonNameModel viewModel;
AutoMapper.Mapper.CreateMap<PersonModel, EditPersonNameModel>();
viewModel = AutoMapper.Mapper.Map<PersonModel, EditPersonNameModel>(person);
return View(viewModel);
}
А мой блок кода для #2
выглядит следующим образом:
[HttpPost]
public ActionResult EditName(EditPersonNameModel viewModel, int id) {
if (ModelState.IsValid) {
PersonModel person = db.Persons.Find(id);
if (person == null) {
return HttpNotFound();
}
EditPersonNameModel viewModel;
AutoMapper.Mapper.CreateMap<EditPersonNameModel, PersonModel>();
person = AutoMapper.Mapper.Map<EditPersonNameModel, PersonModel>(viewModel);
db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
#1
выше на самом деле работает нормально.AutoMapper будет отображаться из более крупного объекта Person в объект EditPersonName.
#2
выше, однако, не работает.AutoMapper отобразит из объекта EditPersonNameModel новый объект Person и, следовательно, db.Entry(person).State = EntityState.Modified
сгенерирует исключение:
Объект с таким же ключом уже существует в ObjectStateManager.ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом.
Мне не нужен AutoMapper для создания нового объекта, мне нужно сопоставить существующий объект .Если бы только было AutoMapper.Mapper.
Обновление <EditPersonNameModel, PersonModel>(viewModel, person)
.
Хорошо, так что теперь это очень длинный вопрос!Спасибо за чтение, и я очень ценю вашу помощь!Если вы знакомы с AutoMapper и знаете, что я делаю что-то не так, пожалуйста, дайте мне знать.Если вы читаете этот код и знаете другой способ сделать это вообще, пожалуйста, дайте мне знать это тоже!
Спасибо !!!
Обновление 1
У меня #2
работает, но я не уверен, насколько он хорош.
Новый #2
[HttpPost]
public ActionResult EditName(EditPersonNameModel viewModel, int id) {
if (ModelState.IsValid) {
PersonModel person = db.Persons.Find(id);
if (person == null) {
return HttpNotFound();
}
TryUpdateModel(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
Обратите внимание, что TryUpdateModel
вызывается на person
, а не viewModel
.Я уже получил person
из базы данных, поэтому она полностью заполнена с идентификатором.Метод TryModelUpdate
использует IModelBinder
для сопоставления свойств из текущего "контекста запроса mvc" с указанным объектом.Поскольку мои PersonModel
и EditPersonNameModel
используют одни и те же именованные свойства, это работает.Это действительно очень плохое решение, поэтому, если вы знаете что-то лучше, пожалуйста, дайте мне знать!