【问题标题】:Correct way to edit and update complex viewmodel objects using asp.net-mvc2 and entity framework使用 asp.net-mvc2 和实体框架编辑和更新复杂视图模型对象的正确方法
【发布时间】:2010-04-02 22:12:16
【问题描述】:

我的数据库中有一个表与另一个表有一对多关系,而另一个表又与第三个表有关系:

父对象

  • 身份证
  • 名称
  • 说明

子对象

  • 身份证
  • 名称
  • 说明
  • 父对象ID
  • 另一个对象 ID

另一个对象

  • 身份证
  • 名称

对象被映射到实体框架并通过数据访问类公开。

当要显示的数据与领域对象有很大差异时,似乎建议使用 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 个相关的“另一个对象”。 1 '另一个对象' 是预期的。

对 StackOverflow 和一般谷歌搜索的调查让我找到了 this blog post,这似乎描述了我的问题:TryUpdateModel() 不能正确处理嵌套集合。显然,(并且通过调试器确认了这一点)它创建了一个新的 ChildObject 而不是与我实例化上下文中的 EF 对象相关联。

我的 hacky 工作是这样的:

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 - 我试图清理代码以隐藏特定信息,所以要小心我可能已经搞砸了。我主要只是想知道其他人是否解决了这个问题。

【问题讨论】:

  • 很抱歉把这个备份起来,但我遇到了类似的问题。无法弄清楚如何将我的所有数据访问保持在视图、控制器和存储库之间的相同“上下文”中。 .所以我在我的数据库中得到了重复..你找到了做这一切的“正确方法”吗?谢谢
  • 我们最终通过在复杂情况下不使用 TryUpdateModel 基本上解决了这个问题。不过,您的问题听起来不同,您可能会考虑从上下文中分离/附加实体。

标签: c# asp.net entity-framework asp.net-mvc-2


【解决方案1】:

只是简单地看一下提到 FK_ChildObject_AnotherObject... 的错误,您确定您的 EF 数据模型中有关 AnotherObject 的所有内容都正确连接了吗?

在您的问题中,您只列出了两个表,但此错误表明 ChildObject 正在参与与 AnotherObject 的 1 到 * 关系,并且保存时实体中不存在导致错误的表。

尝试从情境中删除 AnotherObject 以测试 ParentObject 和 ChildObject 之间的任何假设问题,或尝试将 FK_ChildObject_AnotherObject 关系更改为 0..1 到 * 进行短暂测试。

【讨论】:

  • 我很抱歉没有在我的简要概述中包含第三个表格。我已经编辑了原始帖子以包含第三个表格。根据您的建议,我将 AnotherObject 表设为 0..1。这会将错误更改为:正在从 AssociationSet 'FK_ChildObject_ParentObject' 添加或删除关系。使用基数约束,还必须添加或删除相应的“ChildObject”。这似乎暗示 EF 认为我正在尝试创建另一个 ChildObject...我什至尝试完全删除 AnotherObject 关系,但我仍然遇到相同的错误。
  • 嗯,好消息是AnotherObject现在已经不在了,重点是它所属的地方,也就是Parent和Child的关系。您是否仍然通过添加/删除孩子来产生此错误?此错误似乎表明您主要在处理 Parent 。就像,您添加了一个父级,但父/子关联是 * 到 1 而不是 * 到 0..1。在这种情况下添加父级将要求存在一个子级,并可能产生与您类似的错误。
【解决方案2】:

您可以考虑使用 Omu ValueInjector 而不是 tryupdate。虽然我更喜欢按惯例使用它,但它可以配置得更智能。

tbh 这里的原始问题并不完全清楚。我不确定为什么视图模型中的子对象首先与父对象分离?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    相关资源
    最近更新 更多