ASP.NET MVC 3如何在Create视图上为具有ICollection属性的Model提供多字段创建功能

时间:2011-01-03 20:18:48

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

注意:我正在使用 MVC3 + Razor,EF4,CF-CTP5

  1. 如何让视图能够在客户端上动态地为每个组织添加多个地址类,并在帖子上强烈绑定到模型?

  2. 如果(ModelState.IsValid == false)如何输入3个地址并发布无效模型,如何在模型中使用视图解析值,它会重新填充数字地址并使用它们适当的价值?

  3. 以下是我的模特:

    public class Organization
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Address> Addresses { get; set; }
        public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
        ...
    }
    
    public class Address
    {
        public int Id { get; set; }
        public string Line1 { get; set; }
        public string Line2 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public int Type { get; set; }
    }
    

    我正在试图弄清楚如何让组织(/组织/创建)的创建操作处理创建(如此地址和电话号码是提交模型的一部分):

    [HttpPost]
    public ActionResult Create(Organization organization)
    {
        if (ModelState.IsValid)
        {
            _db.Organizations.Add(organization);
            _db.SaveChanges();
            return RedirectToAction("Details", organization.Id);
        }
    
        return View(organization);
    
    }
    

3 个答案:

答案 0 :(得分:1)

你的问题很有趣:) 这只是您的要求之一,我相信有比我更好的方式。

我将从你的第二个问题开始:

  

如何使用视图解析值   在模型中如果   (ModelState.IsValid == false)这样的   如果您输入3个地址并发布   一个无效的模型,它重新填充   号码地址和他们的   适当的价值观?

如果我正确理解您的请求,对我来说看起来很简单。答案就是 编码您的视图以呈现模型类内容 ,并将无效模型返回到客户端,就像您在Create操作中一样。< / p>

如果您的表单(及其字段)已使用ValidationSummary/ValidationMessage html帮助程序进行修饰,您还将看到验证消息。

  
      
  1. 如何让视图能够添加多个地址   每个组织的类动态   在客户端,并强烈约束   帖子上的模型?
  2.   

您可以拥有一个显示组织属性的主视图,然后有另一个显示相关地址的视图。在这里,您可以放置​​一个超链接或按钮,打开一个对话框以添加新的地址对象,然后在完成后刷新地址列表。同样,您可以在列表中编辑和删除按钮作为图标。

地址列表是在客户端完全处理的一个标记,要正确绑定到服务器端,Model类应该遵循一些简单的命名规则来获取它的输入属性。

要使默认模型Binder类正确绑定您的表单,请使用以下代码段为您的Organization

@using (Html.BeginForm()) {
    @Html.HiddenFor(o => o.Id)
    @Html.ValidationSummary( true )
    <fieldset>
        <legend>My Organization</legend>
        <div class="editor-label">@Html.LabelFor( model => model.Name )</div>
        <div class="editor-field">
            @Html.EditorFor( model => model.Name )
            @Html.ValidationMessageFor( model => model.Name )
        </div>
        <br />
        <div id="container">
            <div>Address List</div>
            @foreach (Address a in Model.Addresses ) {
                Html.EditorFor(a);
            }
        </div>
        <div style="text-align:right;margin-top:14px;">
            <input type="submit" id="btnSubmit" value="Save" />
        </div>
    </fieldset>
}

要自动绑定,表单的结果代码应如下所示

<form action="..." id="..." method="post">
    <input type="hidden" name="Id" value="2">
    <input type="hidden" name="Name" value="Acme Corporation">

    <!-- markup for each address -->
    <input type="hidden" name="Addresses[0].Id" value="1">
    <input type="hidden" name="Addresses[0].Line1" value="Line 1">
    <input type="hidden" name="Addresses[0].Line2" value="Line 2">
    ... and so on...
</form>

将其属性命名为Addresses[index].PropertyName。 如果您在客户端上添加新地址,那么这并不重要:只要您的代码遵守此规则,您就可以使用默认的Model Binder为您完成工作。

希望这有帮助

答案 1 :(得分:0)

我不确定我是否正确理解了您的问题,但就问题1而言,我认为您正在寻找一个ViewModel。像这样或许..

OrganizationViewModel.cs

public class OrganizationViewModel
{
  public OrganizationViewModel(Organization org, IList<Address> addresses)
     {
       this.Organization = org;
       this.Addresses = addresses
     }
     public Organization Organization {get;set;}
     public IList<Address> Addresses {get;set;}
}

OrganizationController.cs

public class OrganizationController : Controller
{
  private readonly IOrganizationService _organizationService: //or whatever method you use
  public OrganizationController(IOrganizationService orgService)
     {
       this._organizationService = orgService;
     }

   public ActionResult Item(int id)
     {
       var org = _organizationService.GetOrganizationById(id);
       var addresses = _organizationService.GetOrgAddressesByOrgId(id);
       return View(new OrganizationViewModel(program, addresses));
     }
}

Item.cshtml

@model OrganizationViewModel
<h1>@Model.Organization.Name</h1>
<ul>
@foreach(var a in Model.Addresses)
{
<li>@a.Line1</li>
<li>@a.Line2</li>}
</ul>

在我尝试回答2号之前,你应该说明我是否正确理解问题1.希望这会有所帮助。

答案 2 :(得分:0)

我设法使用LINQ to SQL执行此操作。现在我正在尝试使用实体框架,但它确实使一切变得更加复杂。所以我没有为您提供解决方案,但也许我的L2S解决方案可能有所帮助?

使用从我的数据库生成的模型,我可以在我看来这样做:

@for (int i = 0; i < Model.Contact.EmailAddresses.Count; ++i)
{
    <li>
        @Html.TextBoxFor(x => x.Contact.EmailAddresses[i].EmailAddress)
        @Html.HiddenFor(x => x.Contact.EmailAddresses[i].EmailAddressID)
    </li>
} 

我有一个视图模型类:

class ContactViewModel
{
    Contact contact { get; set; }
}

这很好用,在我的控制器操作中,我得到了我的Contact对象,其中的Contact.ContactEmailAddresses列表就像我预期的那样填充。

但是对于EF,我不能再使用从数据库生成的EmailAddresses属性上的[i]。我想出的最好的是:

@Html.TextBox("Contact.EmailAddresses[" + i + "].EmailAddress", Model.Contact.EmailAddresses.ElementAt(i).EmailAddress)