实体框架TryUpdateModel子对象?

Sam*_*Sam 3 asp.net asp.net-mvc entity-framework entity-framework-4.1 asp.net-mvc-3

我知道大多数人会建议我应该使用特定于我正在使用的表单的ViewModel,但我很好奇为什么我的子对象没有在TryUpdateModel上绑定.

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>User</legend>

        @Html.HiddenFor(model => model.UserId)
    @Html.HiddenFor(model => model.PrimaryAddress.AddressId)
    <div class="editor-label">
            @Html.LabelFor(model => model.PrimaryAddress.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PrimaryAddress.FirstName)
            @Html.ValidationMessageFor(model => model.PrimaryAddress.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PrimaryAddress.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PrimaryAddress.LastName)
            @Html.ValidationMessageFor(model => model.PrimaryAddress.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UserName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UserName)
            @Html.ValidationMessageFor(model => model.UserName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Email)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Email)
            @Html.ValidationMessageFor(model => model.Email)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsApproved)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsApproved)
            @Html.ValidationMessageFor(model => model.IsApproved)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsEmployee)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsEmployee)
            @Html.ValidationMessageFor(model => model.IsEmployee)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}
Run Code Online (Sandbox Code Playgroud)

和控制器代码:

[HttpPost]
public ActionResult Edit(int id, FormCollection form)
{
    var user = Token.DB.Users.Include("PrimaryAddress").Single(x => x.UserId == id);
    if (TryUpdateModel(user, new string[] { "UserName", "Email", "IsApproved", "IsEmployee", "PrimaryAddress.FirstName", "PrimaryAddress.LastName" }))
    {
        try
        {
            Token.DB.SaveChanges();
            return RedirectToAction("index");
        }
        catch (Exception ex)
        {
            while (ex.InnerException != null)
                ex = ex.InnerException;
            if (ex.Message.ToLowerInvariant().Contains("unique"))
                ModelState.AddModelError("UserName", "UserName already exists");
        }
    }
    return View(User);
}
Run Code Online (Sandbox Code Playgroud)

代码不会抛出任何异常,它只是不填充表单中的user.PrimaryAddress.FirstName或user.PrimaryAddress.LastName.我想知道为什么?

我已经知道我可以使用特定的ViewModel解决问题并在后台映射信息.我也可以这样做:

<!-- Edit.cshtml -->
<div class="editor-field">
    @Html.EditorFor(model => model.PrimaryAddress.FirstName, null, "FirstName")
    @Html.ValidationMessageFor(model => model.PrimaryAddress.FirstName)
</div>

<div class="editor-label">
    @Html.LabelFor(model => model.PrimaryAddress.LastName)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.PrimaryAddress.LastName, null, "LastName")
    @Html.ValidationMessageFor(model => model.PrimaryAddress.LastName)
</div>

// UsersController.cs
if (TryUpdateModel(user, new string[] { "UserName", "Email", "IsApproved", "IsEmployee"})
&& TryUpdateModel(user.PrimaryAddress, new string[] {"FirstName", "LastName" }))
Run Code Online (Sandbox Code Playgroud)

所以真正的问题是为什么在第一个例子中它不具有约束力?

Dar*_*rov 9

所以真正的问题是为什么在第一个例子中它不具有约束力?

您的问题的答案非常简单:UpdateModel,TryUpdateModel或[Bind]属性都不支持include/exclude属性列表中的"嵌套属性".所以要正确地做事并使用视图模型.防止大规模属性分配攻击只是您应该使用视图模型的数百万个原因之一.好吧,你好像通过执行第二次找到了一种解决方法,TryUpdateModel但如果你在这个域对象上有很多属性,你的控制器动作代码很快就会变成意大利面条管道代码.