简体   繁体   English

使用asp.net-mvc2和实体框架编辑和更新复杂的viewmodel对象的正确方法

[英]Correct way to edit and update complex viewmodel objects using asp.net-mvc2 and entity framework

I have a table in my database with a one to many relationship to another table, which has a relationship to a third table: 我的数据库中有一个表,该表与另一个表具有一对多关系,而另一个表与第三个表有关系:

ParentObject 父对象

  • ID ID
  • Name 名称
  • Description 描述

ChildObject 子对象

  • ID ID
  • Name 名称
  • Description 描述
  • ParentObjectID ParentObjectID
  • AnotherObjectID AnotherObjectID

AnotherObject 另一个对象

  • ID ID
  • Name 名称

The objects are mapped into Entity Framework and exposed through a data access class. 这些对象被映射到Entity Framework中,并通过数据访问类公开。

It seemed like ViewModels are recommended when the data to be displayed greatly differs from the domain object, so I created a ViewModel as follows: 当要显示的数据与域对象有很大差异时,似乎建议使用ViewModels,因此我按如下方式创建了ViewModel:

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

I have a view that displays a list of ParentObjects and when clicked will allow a ChildObject to be modified saved. 我有一个视图,该视图显示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>
    <% }
}
} %>  

This all works fine. 这一切都很好。 My question is around the best way to update the EF objects and persist the changes back to the database. 我的问题是围绕更新EF对象并将更改保存回数据库的最佳方法。 I initially tried: 我最初尝试:

[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");
    }

When I try to save a change to the child object, I get this exception: Entities in 'MyEntities.ChildObject' participate in the 'FK_ChildObject_AnotherObject' relationship. 当我尝试将更改保存到子对象时,出现此异常:'MyEntities.ChildObject'中的实体参与'FK_ChildObject_AnotherObject'关系。 0 related 'AnotherObject' were found. 找到0个相关的'AnotherObject'。 1 'AnotherObject' is expected. 1'AnotherObject'是预期的。

Investigation on StackOverflow and general googling led me to this blog post that seems to describe my problem: TryUpdateModel() does not correctly handle nested collections. 对StackOverflow和常规搜索的调查使我转向了这篇博客文章该文章似乎描述了我的问题:TryUpdateModel()无法正确处理嵌套集合。 Apparently, (and stepping through the debugger confirms this) it creates a new ChildObject instead of associating with the EF objects from my instantiated context. 显然,(并逐步通过调试器确认了这一点)它将创建一个新的ChildObject,而不是与我实例化的上下文中的EF对象关联。

My hacky work around is this: 我的变通方法是这样的:

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;
    }
}

This seems to work fine. 这似乎很好。 My question to you good folks: Is there a correct way to do this? 我对各位老兄的问题是:是否有正确的方法来做到这一点? I tried following the suggestion for making a custom model binder per the blog link I posted above but it didn't work (there was an issue with reflection, the code expected certain properties to exist) and I needed to get something going ASAP. 我尝试按照上面发布的博客链接创建自定义模型联编程序的建议,但没有成功(反射存在问题,代码预期某些属性存在),因此我需要尽快采取措施。

PS - I tried to cleanup the code to hide specific information, so beware I may have hosed something up. PS-我试图清理代码以隐藏特定信息,所以请注意,我可能已经整理了一些东西。 I mainly just want to know if other people have solved this problem. 我主要只是想知道其他人是否解决了这个问题。

Just briefly looking at the error mentioning FK_ChildObject_AnotherObject... are you sure everything is wired up correctly in your EF data model concerning AnotherObject? 只是简单地看一下提到FK_ChildObject_AnotherObject ...的错误...您确定在与AnotherObject有关的EF数据模型中所有内容都正确连接了吗?

In your question you only list two tables, but this error is indicating that the ChildObject is participating in a 1 to * relationship with AnotherObject and there is not one present in the entity on save causing an error. 在您的问题中,您仅列出了两个表,但是此错误表明ChildObject正在与AnotherObject进行从1到*的关系,并且保存时实体中不存在任何一个,从而导致错误。

Try removing AnotherObject from the situation in order to test any assumed problems between ParentObject and ChildObject, or try changing the FK_ChildObject_AnotherObject relationship to 0..1 to * briefly for testing. 尝试从这种情况下删除AnotherObject以便测试ParentObject和ChildObject之间的任何假定问题,或尝试将FK_ChildObject_AnotherObject关系从0..1短暂更改为*以进行测试。

You could look at using Omu ValueInjector instead of tryupdate. 您可以看看使用Omu ValueInjector而不是tryupdate。 It can be configured to be much smarter although I prefer to use it by convention. 尽管我更喜欢按惯例使用它,但它可以配置为更加智能。

tbh not entirely clear on the original question here. 在这里对原始问题还不完全清楚。 I'm not sure why the childobjects in the viewmodel are being detached form the parent in the first place? 我不确定为什么首先将视图模型中的子对象与父对象分离?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM