在单个视图上更新模型和模型集合(MVC4)

时间:2013-09-11 15:01:15

标签: c# asp.net-mvc asp.net-mvc-4

我一直在研究MVC 4应用程序,并且在尝试更新ViewModel中的模型时遇到了问题。

我的ViewModel(详情如下)包含一个ComplexObjectOne和一个List<ComplexObjectTwo>

我的 GET ActionResult已成功填充数据库中的ViewModel,并且所有内容都在View上正确显示。

尝试将ComplexObjectOneList<ComplexObjectTwo>传递给 POST ActionResult时遇到问题。

ComplexObject已正确传递,但我尝试过的所有内容都无法通过List<ComplexObjectTwo>集合。

我的ComplexModelOne Model

public class Test
{
    public int Id {get;set;}
    public string Result {get;set;}

    public virtual ICollection<TestResult> TestResults {get;set;}
}

我的ComplexModelTwo Model

public class TestResult
{
    public int Id {get;set;}
    public string Result {get;set;}
    public string Comment {get;set;}

    public virtual Test Test{get;set;}
}

我的ViewModel

public class TestingViewModel
{
    public TestingViewModel()
    {
        if(TestResults == null)
        {
            TestResults = new List<TestResult>();
        }
    }

    public Test Test {get;set;}
    public IEnumerable<TestResult> TestResults {get;set;}
}

我的编辑()获取 ActionResult

public ActionResult Edit(int id = 0)
    {
        var viewModel = new TestingViewModel();

        Test test = testRepo.GetTestById(id);
        var results = test.TestResults;

        viewModel.Test = test;
        viewModel.TestResults = results;
        return View(viewModel);
    }

我的编辑()发布 ActionResult

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(TestingViewModel model)
{
    // do update - left out for brevity
}

我的Edit.cshtml View

@model Namespace.Models.ViewModels.TestingViewModel

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)


    @Html.EditorFor(model => model.Test, "TestHeader")

    <table>
        <tr>
            <th>Test</th>
            <th>Result</th>
            <th>Comment</th>
        </tr>
        @Html.EditorFor(model => model.TestResults, "TestResults")

    </table>

    <input type="submit" value="Update"/>
}

在我的View中,我确实使用了几个EditorTemplates来显示属性字段。

非常感谢任何帮助,评论或建议。我希望能够在单个页面上完成更新这些实体,而不是在Create()步骤中使用多个页面。

谢谢,

Patrick H.(stpatrck)

1 个答案:

答案 0 :(得分:1)

替换:

@Html.EditorFor(model => model.TestResults, "TestResults")

使用:

@Html.EditorFor(model => model.TestResults)

然后将您的EditorTemplates/TestResults.cshtml编辑器模板重命名为EditorTemplates/TestResult.cshtml(注意缺少的s)并在里面替换模型声明:

@model IEnumerable<TestResult>

为:

@model TestResult

现在显然这将导致摆脱您在此编辑器模板中编写的任何forforeach循环,因为现在ASP.NET MVC将自动为集合的每个元素调用模板

例如:

@foreach (var item in Model)
{
    @Html.EditorFor(x => item.SomeProperty)
}

将简单地成为:

@Html.EditorFor(x => x.SomeProperty)

现在查看生成的标记,并注意输入字段名称的差异。在你之前:

<input type="text" name="item.SomeProperty" value="foo" />

现在你有:

<input type="text" name="TestResults[0].SomeProperty" value="foo" />

现在,当您将表单提交到POST操作时,默认模型绑定器将能够成功绑定集合,因为现在遵循命名约定。您可以在following blog post中了解有关此约定的更多信息。

您的对象图中也有循环引用,无法成功序列化和模型绑定。您应该使用视图模型来打破这种循环依赖。