Правильный способ редактировать и обновлять сложные объекты viewmodel, используя asp.net-mvc2 и каркас сущностей - PullRequest
8 голосов
/ 03 апреля 2010

В моей базе данных есть таблица с отношением один ко многим к другой таблице, которая имеет отношение к третьей таблице:

ParentObject

  • ID
  • Имя
  • Описание

ChildObject

  • ID
  • Имя
  • Описание
  • ParentObjectID
  • AnotherObjectID

AnotherObject

  • ID
  • Имя

Объекты отображаются в Entity Framework и предоставляются через класс доступа к данным.

Казалось, что ViewModel рекомендуется, когда отображаемые данные сильно отличаются от объекта домена, поэтому я создал ViewModel следующим образом:

public class ViewModel {
    public IList<ParentObject> ParentObjects { get; set; }
    public ParentObject selectedObject { get; set; }
    public IList<ChildObject> ChildObjects { get; set; }
}

У меня есть представление, которое отображает список ParentObjects и при щелчке на него позволяет сохранить сохраненный объект ChildObject.

<% using (Html.BeginForm()) { %> 
<table>
    <% foreach (var parent in Model.ParentObjects) { %>
    <tr>
        <td>
            ObjectID [<%= Html.Encode(parent.ID)%>]
        </td>
        <td>
            <%= Html.Encode(parent.Name)%>
        </td>
        <td>
            <%= Html.Encode(parent.Description)%>
        </td>
    </tr>
    <% } %>
</table>
<% if (Model.ParentObject != null) { %>
<div>
    Name:<br />
    <%= Html.TextBoxFor(model => model.ParentObject.Name) %>
    <%= Html.ValidationMessageFor(model => model.ParentObject.Name, "*")%>
</div>
<div>
    Description:<br />
    <%= Html.TextBoxFor(model => model.ParentObject.Description) %>
    <%= Html.ValidationMessageFor(model => model.ParentObject.Description, "*")%>
</div>
<div>
    Child Objects
</div>
<% for (int i = 0; i < Model.ParentObject.ChildObjects.Count(); i++) { %>
    <div>
        <%= Html.DisplayTextFor(sd => sd.ChildObjects[i].Name) %>
    </div>
    <div>
        <%= Html.HiddenFor(sd => sd.ChildObjects[i].ID )%>
        <%= Html.TextBoxFor( sd => sd.ChildObjects[i].Description) %>
        <%= Html.ValidationMessageFor(sd => sd.ChildObjects[i].Description, "*") %>
    </div>
    <% }
}
} %>  

Это все отлично работает. Мой вопрос о том, как лучше всего обновить объекты EF и сохранить изменения обратно в базу данных. Я изначально пробовал:

[HttpPost]
    public ActionResult Edit(ViewModel viewModel) {
        ParentObject parent = myRepository.GetParentObjectByID(viewModel.SelectedObject.ID);

        if ((!ModelState.IsValid)
            || !TryUpdateModel(parent, "SelectedObject", new[] { "Name", "Description" })) {
            || !TryUpdateModel(parent.ChildObjects, "ChildObjects", new[] { "Name", "Description" })) {


            //Code to handle failure and return the current model snipped

            return View(viewModel);
        }

        myRepository.Save();

        return RedirectToAction("Edit");
    }

Когда я пытаюсь сохранить изменение в дочернем объекте, я получаю следующее исключение: объекты в «MyEntities.ChildObject» участвуют в отношении «FK_ChildObject_AnotherObject». 0 связанных 'AnotherObject' были найдены. 1 Ожидается еще один объект.

Изучение StackOverflow и общего поиска в Google привело меня к этой записи в блоге , которая, кажется, описывает мою проблему: TryUpdateModel () неправильно обрабатывает вложенные коллекции. По-видимому, (и пошаговое выполнение отладчика подтверждает это) он создает новый ChildObject вместо связи с объектами EF из моего экземпляра.

Моя хакерская работа такова:

if (viewModel.ChildObjects.Count > 0) {
    foreach (ChildObject modelChildObject in viewModel.ChildObjects) {
        ChildObject childToUpdate = ParentObject.ChildObject.Where(a => a.ID == modelChildObject.ID).First();
        childToUpdate.Name = modelChildObject.Name;
    }
}

Кажется, это работает нормально. Мой вопрос к вам, ребята: есть ли правильный способ сделать это? Я попытался следовать предложению сделать привязку пользовательской модели по ссылке в блоге, которую я разместил выше, но это не сработало (возникла проблема с отражением, код ожидал, что определенные свойства будут существовать), и мне нужно было что-то сделать как можно скорее.

PS - Я пытался очистить код, чтобы скрыть конкретную информацию, так что будьте осторожны, я мог что-то спрятать. В основном я просто хочу знать, решили ли другие люди эту проблему.

Ответы [ 2 ]

1 голос
/ 03 апреля 2010

Просто кратко рассмотрим ошибку с упоминанием FK_ChildObject_AnotherObject ... вы уверены, что все правильно подключено в вашей модели данных EF, касающейся AnotherObject?

В вашем вопросе вы перечислите только две таблицы, но эта ошибка указывает на то, что ChildObject участвует в отношении 1 к * с AnotherObject, и в сущности при сохранении нет ни одной, вызывающей ошибку.

Попробуйте удалить AnotherObject из ситуации, чтобы проверить любые предполагаемые проблемы между ParentObject и ChildObject, или попробуйте изменить отношение FK_ChildObject_AnotherObject с 0..1 на * кратко для тестирования.

0 голосов
/ 21 октября 2011

Вы можете посмотреть на использование Omu ValueInjector вместо tryupdate. Он может быть настроен намного умнее, хотя я предпочитаю использовать его по соглашению.

tbh не совсем ясно по первоначальному вопросу здесь. Я не уверен, почему дочерние объекты в модели представления в первую очередь отсоединяются от родителя?

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