何时在MVC3(ASP.NET)中创建模型对象

时间:2011-05-14 22:10:44

标签: asp.net-mvc-3 razor entity-relationship

试图了解何时在MVC3中实例化模型对象:

我有一个编辑“人”的观点;每个人可以有多个地址。我在人物视图的网格中显示地址。

这在展示一个人时效果很好;我有一个部分视图,它遍历Person.Addresses并构建表/网格。

创建新人时会出现问题:person对象为null且Person.Addresses引用是非法的。

我确信我在这里缺少一些相当基本的东西:因为MVC将(自动神奇地)在“保存”上创建新的人物实例;尝试创建我自己的对象实例似乎是反制作的,如果我这样做,我不知道如何将它连接到表单上的其余条目值。

最后一个复杂情况:Addresses列表是可选的;没有地址是完全合法的。

由于关系数据非常普遍,因此必须有一个更简单的解决方案来处理这个问题。所有澄清都表示赞赏!

2 个答案:

答案 0 :(得分:3)

这个问题的答案是,对象是从表单中的POST数据重新构成的。这是相当基本的,但MVC隐藏了很多正在发生的事情,当你试图获得(MVC)轴承时很难看到。

项目顺序为:

  1. 创建包含所有必填字段的表单;将隐藏字段用于非显示键(ID)。
  2. 用户与网页互动;然后按表单提交按钮。
  3. 所有字段数据都会发布到控制器页面。
  4. MVC将数据重新构建为类对象。
  5. 使用重构的类实例作为形式参数调用控制器页面。
  6. 注意:

    创建页面时:生成一个表单,其中包含所表示对象的每个部分的字段。 MVC使用ID和其他非显示数据的隐藏字段以及验证规则 值得注意的是,通过列出_CreateOrEdit.cshtml页面上的所有对象属性(通常)创建表单:

    // Edit.cshtml
    @model Person
    
    @Html.Partial("_CreateOrEdit", Model)
    

    // _CreateOrEdit.cshtml
    @model Person
    
    @Html.HiddenFor(model => model.PersonID)
    
    @Html.LabelFor(model => model.first_name, "First Name")
    @Html.EditorFor(model => model.first_name)
    
    @Html.LabelFor(model => model.last_name, "Last Name")
    @Html.EditorFor(model => model.last_name)
    
    @Html.LabelFor(model => model.favorite_color, "Favorite Color")
    @Html.EditorFor(model => model.favorite_color)
    
    //etcetera
    

    或使用该类的模板(模板必须与它们所代表的类具有相同的名称,并且它们位于Views\Shared\EditorTemplates文件夹中)。

    使用模板页面几乎与以前的方法相同:

    // Edit.cshtml
    @model Person
    
    @Html.EditorForModel()
    

    // Shared\EditorTemplates\Person.cshtml
    @model Person
    
    @Html.HiddenFor(model => model.PersonID)
    
    @Html.LabelFor(model => model.first_name, "First Name")
    @Html.EditorFor(model => model.first_name)
    
    @Html.LabelFor(model => model.last_name, "Last Name")
    @Html.EditorFor(model => model.last_name)
    
    @Html.LabelFor(model => model.favorite_color, "Favorite Color")
    @Html.EditorFor(model => model.favorite_color)
    
    //etcetera
    

    使用模板方法可以轻松地将(对象的)列表添加到表单中。 Person.cshtml成为:

    // Shared\EditorTemplates\Person.cshtml
    @model Person
    
    @Html.HiddenFor(model => model.PersonID)
    
    @Html.LabelFor(model => model.first_name, "First Name")
    @Html.EditorFor(model => model.first_name)
    
    @Html.LabelFor(model => model.last_name, "Last Name")
    @Html.EditorFor(model => model.last_name)
    
    @Html.LabelFor(model => model.favorite_color, "Favorite Color")
    @Html.EditorFor(model => model.favorite_color)
    
    @EditorFor( model => model.Addresses )
    
    //etcetera
    

    // Shared\EditorTemplates\Address.cshtml
    @model Address
    @Html.HiddenFor(model => model.AddressID)
    
    @Html.LabelFor(model => model.street, "Street")
    @Html.EditorFor(model => model.street)
    
    @Html.LabelFor(model => model.city, "City")
    @Html.EditorFor(model => model.city)
    
    //etcetera
    

    MVC将处理为列表中的每个地址创建所需数量的表单条目。

    POST完全正好相反;创建模型对象的新实例,调用默认的无参数构造函数,然后MVC填充每个字段。列表通过反转@Html.EditorFor( model.List )的序列化过程来填充。重要的是要注意,您必须确保您的类为构造函数中的列表创建有效容器,否则MVC的列表重构将失败:

    public class Person
    {
        public List<Address> Addresses;
    
        public Person()
        {
            // You always need to create this List object
            Addresses = new List<Address>();
        }
    
        ...
    }
    

    那封面就是它。幕后有很多事情发生,但它都是可追踪的。

    如果您遇到问题,有两个要点:

    1. 确保您有@Html.HiddenFor(...)所有需要“幸存”返回服务器的行程。
    2. 使用Fiddler或HTTPLiveHeaders(Firefox插件)检查POST数据的内容。这将允许您验证发送回的数据以重新构成新的类实例。我对Fiddler很偏爱,因为你可以在任何浏览器中使用它(它可以很好地显示表单数据)。
    3. 最后一点:有一篇关于使用MVC从列表中动态添加/删除元素的文章很好:http://jarrettmeyer.com/post/2995732471/nested-collection-models-in-asp-net-mvc-3这是一篇很好的文章 - 是的,它确实适用于MVC3和Razor。 / p>

答案 1 :(得分:0)

我假设的地址在表中,而不是实际的输入元素,可能只是&lt; td&gt; info&lt; / td&gt;? 如果是这样,那么它们将不会被实例化,因为没有数据被发回服务器。 您必须使用回发的元素创建此数据,以便将它们(按名称)映射到其属性。模型绑定器将实例化对象,并在回发时将它们传递给控制器​​,如果它可以找到适当命名的已发布表单(或查询字符串)元素。