【问题标题】:When are model objects created in MVC3 (ASP.NET)何时在 MVC3 (ASP.NET) 中创建模型对象
【发布时间】:2011-05-14 22:10:43
【问题描述】:

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

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

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

新建person时出现问题:person对象为null,Person.Addresses引用非法。

我确定我在这里遗漏了一些相当基本的东西:因为 MVC 将(自动神奇地)在“保存”时创建新的人实例;尝试创建我自己的对象实例似乎适得其反,如果我这样做了,我将不清楚如何将它连接到表单上的其余条目值。

最后一个问题:Addresses 的列表是可选的;完全没有地址是完全合法的。

由于关系数据如此普遍,因此必须有一个更简单的解决方案来处理这个问题。感谢所有澄清!

【问题讨论】:

  • 所以你实际上不是在编辑一个人,你是在创建一个人?
  • 正确。编辑人员时,模型对象已经存在。创建人时,模型对象为空。

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


【解决方案1】:

这个问题的答案是对象是从表单中的 POST 数据重新构成的。这是相当基本的,但 MVC 隐藏了太多正在发生的事情,以至于当您尝试了解 (MVC) 方位时很难看到。

项目的顺序是:

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

注意事项:

创建页面时:生成一个表单,其中包含所表示对象的每个部分的字段。 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,因为您可以在任何浏览器上使用它(而且它可以很好地显示表单数据)。

最后一点:有一篇关于使用 MVC 从列表中动态添加/删除元素的好文章:http://jarrettmeyer.com/post/2995732471/nested-collection-models-in-asp-net-mvc-3 这是一篇值得阅读的好文章——是的,它确实适用于 MVC3 和 Razor。

【讨论】:

    【解决方案2】:

    我假设的地址在表格中,而不是实际的输入元素,可能只是

    info? 如果是这样,那么它们将不会被实例化,因为没有数据被发送回服务器。 您必须使用回发的元素创建此数据,以便将它们映射(按名称)到它们的属性。如果模型绑定器可以找到适当命名的已发布表单(或查询字符串)元素,则模型绑定器将实例化对象并在回发时将它们传递给您的控制器。

    【讨论】:

    • 那么,您是否会将地址表附加到元素列表中,以便它可以成为 POST 数据的一部分?如果是这样,您将如何做到这一点?
    • @Robert 最简单的方法是做一些 AJAXish,就像 SO 上的评论系统如何工作一样。当您单击添加评论时,评论会通过 AJAX 发布,并且 div 会更新为新内容。您可以使用强类型的局部视图来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    相关资源
    最近更新 更多