试图了解何时在MVC3中实例化模型对象:
我有一个编辑“人”的观点;每个人可以有多个地址。我在人物视图的网格中显示地址。
这在展示一个人时效果很好;我有一个部分视图,它遍历Person.Addresses
并构建表/网格。
创建新人时会出现问题:person对象为null且Person.Addresses
引用是非法的。
我确信我在这里缺少一些相当基本的东西:因为MVC将(自动神奇地)在“保存”上创建新的人物实例;尝试创建我自己的对象实例似乎是反制作的,如果我这样做,我不知道如何将它连接到表单上的其余条目值。
最后一个复杂情况:Addresses
列表是可选的;没有地址是完全合法的。
由于关系数据非常普遍,因此必须有一个更简单的解决方案来处理这个问题。所有澄清都表示赞赏!
答案 0 :(得分:3)
这个问题的答案是,对象是从表单中的POST数据重新构成的。这是相当基本的,但MVC隐藏了很多正在发生的事情,当你试图获得(MVC)轴承时很难看到。
项目顺序为:
注意:
创建页面时:生成一个表单,其中包含所表示对象的每个部分的字段。 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>();
}
...
}
那封面就是它。幕后有很多事情发生,但它都是可追踪的。
如果您遇到问题,有两个要点:
@Html.HiddenFor(...)
所有需要“幸存”返回服务器的行程。最后一点:有一篇关于使用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;? 如果是这样,那么它们将不会被实例化,因为没有数据被发回服务器。 您必须使用回发的元素创建此数据,以便将它们(按名称)映射到其属性。模型绑定器将实例化对象,并在回发时将它们传递给控制器,如果它可以找到适当命名的已发布表单(或查询字符串)元素。