В моей базе данных есть таблица с отношением один ко многим к другой таблице, которая имеет отношение к третьей таблице:
ParentObject
ChildObject
- ID
- Имя
- Описание
- ParentObjectID
- AnotherObjectID
AnotherObject
Объекты отображаются в 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 - Я пытался очистить код, чтобы скрыть конкретную информацию, так что будьте осторожны, я мог что-то спрятать. В основном я просто хочу знать, решили ли другие люди эту проблему.