Как я могу обновить пользовательскую модель представления, используя ASP MVC с DbContext - PullRequest
1 голос
/ 05 декабря 2011

У меня есть модель БД, для которой я хотел бы редактировать несколько видов.Моя фактическая модель БД намного больше, чем та, которую я показываю здесь.

Модель БД: 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 используют одни и те же именованные свойства, это работает.Это действительно очень плохое решение, поэтому, если вы знаете что-то лучше, пожалуйста, дайте мне знать!

1 Ответ

2 голосов
/ 05 декабря 2011

Я бы порекомендовал использовать Automapper или подобное решение, в mvc 3 нет встроенной поддержки отображения модели-> модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...