ASP.NET MVC 表单提交多层子级实体集合数据到控制器中

于遇到了项目中实体类嵌套多层子级实体集合,并且子级实体集合的数据需要提交保存到数据库中的问题。针对此情况需要进行一些特殊的处理才可以将整个 实体类及子级实体集合数据提交表单到控制器中,解决的方法是根据MVC视图中表单的命名规则来设置正确的子级实体集合所属的表单控件name属性,从而来 获取提交的集合数据。

在说明如何将表单中实体的子级实体集合数据提交到控制器中的问题前,我们需要了解MVC的对于数组和列表集合的表单提交方式(点击此链接进行查看)。

定义多层嵌套实体和假设场景

首先我们根据情况进行分析,假设当前有三个实体类,分别为公司类、部门类和员工类,公司类中包含该公司所属部门的实体集合,部门类又包含该部门所属员工的实体集合。

如下代码:

    /// <summary>
    /// 公司实体类
    /// </summary>
    public class Company
    {
        public int ID { get; set; }
        /// <summary>
        /// 公司名称
        /// </summary>
        public string CompanyName { get; set; }
        /// <summary>
        /// 公司地址
        /// </summary>
        public string Address { get; set; }

        /// <summary>
        /// 该公司所属的部门实体集合
        /// </summary>
        public IList<Dept> Depts { get; set; }
    }

    /// <summary>
    /// 部门实体类
    /// </summary>
    public class Dept
    {
        public int ID { get; set; }
        /// <summary>
        /// 所属公司ID
        /// </summary>
        public int CompanyId { get; set; }

        /// <summary>
        /// 部门名称
        /// </summary>
        public string DeptName { get; set; }

        /// <summary>
        /// 该部门所属的员工实体集合
        /// </summary>
        public IList<Employee> Employees { get; set; }
    }

    /// <summary>
    /// 员工实体类
    /// </summary>
    public class Employee
    {
        public int ID { get; set; }
        /// <summary>
        /// 所属部门ID
        /// </summary>
        public int DeptId { get; set; }
        /// <summary>
        /// 员工姓名
        /// </summary>
        public string EmployeeName { get; set; }
    }

那么现在我们假设要增加一个功能,能在页面上同时显示公司、部门和员工的信息,并且在页面上可以提交数据修改,那么我们就要使用到MVC的子级实体集合提交的技巧。

获取实体及子级实体集合在视图中对应的表单控件数据绑定方式

如果我们使用MVC的Helper类的Html.EditorFor方法来获取和绑定数据,那提交数据就显得十分简单了,首先在默认的Index控制器中动态添加了一些测试数据,代码如下:

        [HttpGet]
        public ActionResult Index()
        {
            Company company = new Company();
            company.Address="XXX省XXX市XXX区XXX街XXX号";
            company.CompanyName="XXXXX公司";
            company.ID=1;
            List<Dept> depts = new List<Dept>();
            for (int i = 0; i < 5; i++)
            {
                Dept dept = new Dept();
                dept.ID = i;
                dept.CompanyId = 1;
                dept.DeptName = string.Format("第[{0}]号部门",i.ToString());
                List<Employee> employees = new List<Employee>();
                for (int j = 0; j < 6; j++)
                {
                    Employee employee = new Employee();
                    employee.ID = j;
                    employee.EmployeeName = string.Format("员工{0}",j.ToString());
                    employee.DeptId = i;
                    employees.Add(employee);
                }

                dept.Employees = employees;

                depts.Add(dept);
            }
            company.Depts = depts;

            return View(company);
        }

然后我们在视图页面的代码如下:

@model WebApplication5.Models.Company
@using (Html.BeginForm("Edit","Home"))
{
<div>
    <h3>公司信息</h3>
    ID:@Html.EditorFor(c=>c.ID)
    公司名称:@Html.EditorFor(c => c.CompanyName)
    公司地址:@Html.EditorFor(c => c.Address)
</div>
<div>
    <h3>部门信息</h3>
    @for (int i = 0; i < Model.Depts.Count; i++)
{
    <div>
        <label>ID:</label>
        @Html.EditorFor(c => c.Depts[i].ID)
        <label>部门名称:</label>
        @Html.EditorFor(c => c.Depts[i].DeptName)
        <label>所属公司ID:</label>
        @Html.EditorFor(c => c.Depts[i].CompanyId)
    </div>
}
</div>
<div>
    <h3>员工信息</h3>
    @for (int i = 0; i < Model.Depts.Count; i++)
    {
        for (int j = 0; j < Model.Depts[i].Employees.Count; j++)
        {
        <div>
            <label>ID:</label>
            @Html.EditorFor(c => c.Depts[i].Employees[j].ID)
            <label>员工姓名:</label>
            @Html.EditorFor(c => c.Depts[i].Employees[j].EmployeeName)
            <label>部门ID:</label>
            @Html.EditorFor(c => c.Depts[i].Employees[j].DeptId)
        </div>
        }
    }
</div>
<div>
<input type="submit" value="提交修改"/>
</div>
}

这里我们表单提交到Home控制器的Edit操作方法中。页面使用MVC的HtmlHelper类的EditorFor方法来绑定数 据,HtmlHelper类是一个十分便利的类,根据EditorFor方法我们可以很简单就创建了数据和文本控件的绑定。执行程序最终页面显示的结果如 下(页面简陋了点,不过作为测试页面,不用太在意细节):

我们可以看到无论是Company这个顶级实体,还是Company类下面的Dept子级实体集合,以及Dept类下的Employee子级实体集合,都成功的显示在界面上。

获取提交的子级实体集合数据的多种方法

接下来就是获取提交上来的数据,由于Html.EditorFor方法自动绑定了实体,所以在后台控制器中可以获取到Company类下所有的子级 实体集合的数据。ASP.NET MVC 提供了多种获取子级实体的方法,最常用的是直接在控制器中声明顶级实体类 Company类作为参数,那么就可以通过Company实体来获取下属的Dept子级实体集合和Employee集合。如果想直接获取Dept子级实体 集合,也可以直接在控制器中声明List<Dept> dept 作为参数。但是有一点要注意的是,控制器无法获取第三级以后的子级实体集合数据,因为这些子级数据必须依赖第二级的父实体。以下为表单提交到Home控制 器中的Edit操作方法的代码:

        /// <summary>
        /// 多种方法获取提交上来的子级实体集合数据
        /// </summary>
        /// <param name="compay"></param>
        /// <param name="depts"></param>
        /// <param name="employees"></param>
        /// <returns></returns>
        public ActionResult Edit(Company compay,List<Dept> depts,List<Employee> employees)
        {
            /*
             * 通过Company顶级实体获取各级嵌套的子级实体集合数据
             */
            if (compay != null && compay.Depts != null)
            {
                //获取表单提交上来的公司所属部门实体集合
                foreach (Dept dept in compay.Depts)
                {
                    /*
                     * 省略1000行相关操作代码.......
                     */

                    //获取表单提交上来的公司所属下部门的所属员工自己实体集合数据
                    foreach (Employee employee in dept.Employees)
                    {
                        /*
                         * 省略1000行相关操作代码.......
                         */
                    }
                }
            }
            /*-----------------------------------*/
            /*
             * 通过提交上来的子级实体集合获取数据
             */
            foreach (Dept dept in depts)
            {
                /*
                 * 省略1000行相关操作代码.......
                 */
                //获取所属员工信息
                foreach (Employee employee in dept.Employees)
                {
                    /*
                     * 省略1000行相关操作代码.......
                     */
                }
            }
            /*
             * 注意:这里employees 为null
             * 由于员工作为第三级(最底级)的嵌套,所以无法直接通过提交上来的子级集合获取到,只能依附在Dept下
             * 由此可见通过实体集合只能获取第二级的嵌套
             */
            if (employees != null)
            {
                foreach (Employee employee in employees)
                {
                    /*
                     * 省略1000行相关操作代码.......
                     */
                }
            }
            return Content("");
        }

使用自定义的HTML标签控件获取和提交表单子级实体集合数据

上面是使用HtmlHelper帮助类的方法来绑定数据和提交数据,但是我们也可以直接使用html标签控件来提交和获取表单的子级数据。在这之前 要先了解表单提交数据是如何与ASP.NET MVC控制器中Action方法的参数绑定在一起,这两者的关联是根据<input/>标签的name属性来关联的。假设当前表单中有一输入 控件为<input type="text" name="ID" value="1"/>,那么在所提交的控制中,设置控制器操作方法的参数名为ID,就可以获取name属性等于"ID" 的input标签控件的值。

使用实体绑定的方式也是一个道理,这里可以使用IE11的F12元素选择工具来查看上面用Html.EditorFor方法绑定后最终生成的html代码。

Company实体的ID输入框最终生成HTML代码(这里为了代码简洁,经过部分处理):

<input name="ID" id="ID" type="text" value="1" />

Company实体下所属第一个部门的ID输入框最终生成HTML代码:

<input name="Depts[0].ID" id="Depts_0__ID" type="text" value="0" />

Company实体下所属的第一个部门下,所属的第一个员工ID输入框的HTML代码:

<input name="Depts[0].Employees[0].ID" id="Depts_0__Employees_0__ID" type="text" value="0"/>

从这里应该不难看出MVC对于实体子级集合属性命名规则:

  1. 顶级实体属性对应input标签的name属性的名称是一致的,比如Company.ID对应的就是<input type="text" name="ID"/>
  2. 子级实体的属性对应input标签的name属性的名称,则是父实体的子级集合属性名称加上索引,加上"."和属性名称。比如 Company.Depts[0].ID对应的name属性为Depts[0].ID,完整的html代码为<input name="Depts[0].ID" type="text" value="0" />
  3. 如果是嵌套多级的子级集合,安照上面第二个命名规则即可。比如第三级的Employee子级,Company.Depts[0].Employees对应的name属性为Depts[0].Employees[0].ID

下面为整个使用html input标签来提交和绑定表单数据的完整代码:

@model WebApplication5.Models.Company
@using (Html.BeginForm("Edit","Home"))
{
<div>
    <h3>公司信息</h3>
    ID:<input type="text" name="ID" value="@Model.ID"/>
    公司名称:<input type="text" name="CompanyName" value="@Model.CompanyName"/>
    公司地址:<input type="text" name="Address" value="@Model.Address"/>
</div>
<div>
    <h3>部门信息</h3>
    @for (int i = 0; i < Model.Depts.Count; i++)
{
    <div>
        <label>ID:</label>
        <input type="text" name="Depts[@i].ID" value="@Model.Depts[i].ID" />
        <label>部门名称:</label>
        <input type="text" name="Depts[@i].DeptName" value="@Model.Depts[i].DeptName" />
        <label>所属公司ID:</label>
        <input type="text" name="Depts[@i].CompanyId" value="@Model.Depts[i].CompanyId" />
    </div>
}
</div>
<div>
    <h3>员工信息</h3>
    @for (int i = 0; i < Model.Depts.Count; i++)
    {
        for (int j = 0; j < Model.Depts[i].Employees.Count; j++)
        {
        <div>
            <label>ID:</label>
            <input type="text" name="Depts[@i].Employees[@j].ID" value="@Model.Depts[i].Employees[j].ID" />
            <label>员工姓名:</label>
            <input type="text" name="Depts[@i].Employees[@j].EmployeeName" value="@Model.Depts[i].Employees[j].EmployeeName" />
            <label>部门ID:</label>
            <input type="text" name="Depts[@i].Employees[@j].DeptId" value="@Model.Depts[i].Employees[j].DeptId" />
        </div>
        }
    }
</div>
<div>
<input type="submit" value="提交修改"/>
</div>
}
时间: 2024-10-27 02:16:28

ASP.NET MVC 表单提交多层子级实体集合数据到控制器中的相关文章

ASP.NET MVC 表单的几种提交方式

下面是总结一下在ASP.NET MVC中表单的几种提交方式. 1.Ajax提交表单 需要引用 <script type="text/javascript" src="/Scripts/jquery-1.7.2.min.js"></script>    <script src="/Scripts/jquery.validate.min.js" type="text/javascript">&l

MVC表单提交写法1

初学MVC,感觉跟以前的aspx页面差别很大,我们就先来看看MVC的表单是怎么提交的吧. 现在我们用一个最简单的例子来看一看MVC是怎么提交表单的(这一个例子中,我们的关注点是如何提交表单,所以不涉及到任何的业务逻辑) Model: using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication2.Models { public class

[ASP NET MVC] 表单 Partial View / Editor Template 使用抉择

表单 Partial View / Editor Template 使用抉择 前言 最近有不少同事都会问到"为什么在这边要使用Editor Tamplate? 怎么不用Partial View来做?",其实如果想要知道各自适用的时机,首先就必须了解两者差异为何.从以下表格不难发现,两者都是从VIEW中将ViewModel之Boo属性对象传入Partial View / Editor Template,并且都是使用@Html.EditorFor() 方法来产出Html 元素,但最终产出H

表单提交时如何将错误信息传递到页面中,并且保存原来提交数据

曾经何时,你还有我或许都在困惑,如何方便的将验证不通过的表单信息再返回到前台页面,例如我注册一个账号,辛辛苦苦填写了N多项,一个格式验证没有通过,一切都需要充填,虽然Ajax可以解决这个问题,但是我们总不能把所有表单提交都弄成ajax,更何况有若干人就是没事把javascript给禁止了.哎哎,好了解决方案来了,下面以用户登录为例,说说我的解决方案. 服务器端用nodejs实现: login.html 简单的提交表单 <form action="" id="loginF

asp.net mvc 表单

1. <form action="/controller/action" method="post"> ... </form> *action 属性指定表单要提交到的网页地址 *method 属性指定表单提交时使用的方法(如: get , post) 2. 表单提交按钮可以使用<input type="submit" value="Submit">或<button type="

Spring MVC表单提交

实际应用中,列表中的单条记录的修改,可能需要传很多对象参数到后台服务器,Spring MVC表单标签<form:> 提供了一种简洁的提交方式. 1 <form id="form1" class="form-horizontal chukong_form" method="post" action="${ctx}/channel/sdkversion/postedit.do"> 3 <form:hi

form表单提交数据编码方式和tomcat接受数据解码方式的思考

http://blog.sina.com.cn/s/blog_95c8f1ac010198j2.html ******************************************************* form有2中方法把数据提交给服务器,get和post,分别说下吧. (一)get提交 1.首先说下客户端(浏览器)的form表单用get方法是如何将数据编码后提交给服务器端的吧. 对于get方法来说,都是把数据串联在请求的url后面作为参数,如:http://localhost:

ASP.NET MVC 表单验证

ASP.NET MVC 框架验证每个传递给操作的数据是否有效,控制器操作可以通过查询ModelState来检查请求是否有效,例如,保存有效数据到数据库.后缀返回包含错误提示信息的原始表单给用户.这里是AuctionsController.Create操作,用于判断ModelState的有效性后进行“保存或者返回” 操作: [HttpPost] public ActionResult Create(Auction auction) { if(ModelState.IsValid) { var db

MVC 表单提交【转】

在做Asp.Net MVC项目中,都知道View负责页面展示数据或者提供页面收集数据,而所展示的数据或者收集的数据都是从Controller的Action中获取或提交到Controller的Action. 这里的数据,可能是基础类型,或者是Model,或者是Model的部分内容,或者是集合比如List或Dictionary. 数据从View传递到Controller的Action时,有几种方式,RouteData(url中的路由数据),QueryString(http get的查询参数如?pag