【问题标题】:Propogate Changes to Nested Entities in MVC 3将更改传播到 MVC 3 中的嵌套实体
【发布时间】:2011-07-21 17:47:48
【问题描述】:

我有两个 POCO 类,一个用户和一个地址。地址是一个复杂的对象,一个用户有一个地址。我想创建一个单一的用户视图,允许通过 MVC 脚手架 + 实体框架 + 存储库模式在同一表单上创建/编辑地址。创建用户视图工作正常,但是当我尝试在用户编辑视图中更改地址时,更改不会传播。如何强制更改从用户视图向下传播到地址对象?其他一切都是自动生成的。

POCO 类

public class TestDB : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    }

    public DbSet<Address> Addresses { get; set; }
    public DbSet<User> Users { get; set; }
}

public class Address
{
    public int ID { get; set; }
    public string Street1 { get; set; }
    public string Street2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
}

public class User
{
    public int ID { get; set; }
    public string UserName { get; set; }

    /*[ForeignKey("Address")]
    public int AddressID { get; set; }*/
    public virtual Address Address { get; set; }
}

编辑用户视图

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

    <%: Html.HiddenFor(model => model.ID) %>
        <%: Html.Partial("CreateOrEdit", Model) %>
    <legend>Address</legend>
    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.Street1) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.Street1)%>
        <%: Html.ValidationMessageFor(model => model.Address.Street1)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.Street2)%>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.Street2)%>
        <%: Html.ValidationMessageFor(model => model.Address.Street2)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.City)%>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.City)%>
        <%: Html.ValidationMessageFor(model => model.Address.City)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.State)%>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.State)%>
        <%: Html.ValidationMessageFor(model => model.Address.State)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.PostalCode)%>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.PostalCode)%>
        <%: Html.ValidationMessageFor(model => model.Address.PostalCode)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Address.Country)%>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Address.Country)%>
        <%: Html.ValidationMessageFor(model => model.Address.Country)%>
    </div>
    <p>
        <input type="submit" value="Save" />
    </p>
</fieldset>
<% } %>

<div>
    <%: Html.ActionLink("Back to List", "Index") %>
</div>

地址编辑器模板:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AddressTest.Models.Address>" %>

<script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js") %>" type="text/javascript"></script>

<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
    <legend>Address</legend>

    <%: Html.HiddenFor(model => model.ID) %>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Street1) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Street1) %>
        <%: Html.ValidationMessageFor(model => model.Street1) %>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Street2) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Street2) %>
        <%: Html.ValidationMessageFor(model => model.Street2) %>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.City) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.City) %>
        <%: Html.ValidationMessageFor(model => model.City) %>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.State) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.State) %>
        <%: Html.ValidationMessageFor(model => model.State) %>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.PostalCode) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.PostalCode) %>
        <%: Html.ValidationMessageFor(model => model.PostalCode) %>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(model => model.Country) %>
    </div>
    <div class="editor-field">
        <%: Html.EditorFor(model => model.Country) %>
        <%: Html.ValidationMessageFor(model => model.Country) %>
    </div>

    <p>
        <input type="submit" value="Save" />
    </p>
</fieldset>
<% } %>

<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>

更改为用户编辑视图:

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

    <%: Html.HiddenFor(model => model.ID) %>
        <%: Html.Partial("CreateOrEdit", Model) %>
    <%: Html.Editor("Address", Model.Address) %>

    <p>
        <input type="submit" value="Save" />
    </p>
</fieldset>
<% } %>

【问题讨论】:

    标签: asp.net-mvc-3 entity-framework-4 ef-code-first


    【解决方案1】:

    解决方案是修改用户更新存储库方法并为地址标记实体状态已修改。我还需要在用户编辑视图上为 Address.ID 添加一个隐藏属性。

    用户插入/更新存储库方法

        public void InsertOrUpdate(User user)
        {
            if (user.ID == default(int)) {
                // New entity
                context.Users.Add(user);
            } else {
                // Existing entity
                context.Entry(user.Address).State = EntityState.Modified; // Update Address
                context.Entry(user).State = EntityState.Modified;
            }
        }
    

    用户编辑视图上的附加隐藏属性

    <%: Html.HiddenFor(model => model.ID) %>
    <%: Html.HiddenFor(model => model.Address.ID) %> <!-- Added this line! -->
    

    控制器编辑动作

        // POST: /User/Edit/5
    
        [HttpPost]
        public ActionResult Edit(User user)
        {
            if (ModelState.IsValid) {
                userRepository.InsertOrUpdate(user);
                userRepository.Save();
                return RedirectToAction("Index");
            } else {
                ViewBag.PossibleAddresses = addressRepository.All;
                return View();
            }
        }
    

    【讨论】:

      【解决方案2】:

      这里的技巧可能是使用编辑器模板

      基本上在 Views/Shared/EditorTemplates 中创建一个名为 Address 的局部视图(如果文件夹不存在,则创建该文件夹)并强输入到您的地址类。此模板将包含您的地址编辑器(从上述内容中删除,并将 model => model.Address 更改为 model=>model 。然后将所有地址编辑器从您的视图中取出并放入 EditorFor(model.Address)相反。我认为这会生成稍微不同的字段名。

      【讨论】:

      • Andiih,我通过为地址添加新的编辑器模板应用了您建议的更改。当我从用户编辑视图中进行更改并点击保存时,地址字段的更改仍未被记录。我在底部添加了 2 个新部分,用于编辑器模板和更改为用户编辑视图。
      • 我看到您找到了解决方案,但出于好奇,您的 [HttpPost] 部分的控制器代码是什么?
      • Andiih,我在编辑操作上使用 HttpPost 更新了我的解决方案。希望对您有所帮助。
      猜你喜欢
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 2015-05-09
      • 2012-01-03
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2023-04-03
      相关资源
      最近更新 更多