具有强类型MVC的实体框架

时间:2009-05-21 21:49:29

标签: c# .net asp.net asp.net-mvc entity-framework

我正在使用ASP.NET MVC和ADO.NET实体框架。

我想强烈输入我的视图和控制器。

但我该如何处理实体关联?

这是一个简单的例子:

一个人有一个部门。部门有零个或多个人。

Entity Data Model of Person and Department entities

我的控制器将一个Person对象的实例和所有Department对象的集合传递给View。

public class PersonController : Controller
{
    ...

    //
    // GET: /Person/Create

    public ActionResult Create()
    {
        Person Model = new Person();
        Model.Id = Guid.NewGuid();
        ViewData["Departments"] = db.Department;
        return View(Model);
    } 
    ...
}

我的视图有一个“部门”DropDownList,所有部门都作为选项。

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Id">Id:</label>
            <%= Html.TextBox("Id") %>
            <%= Html.ValidationMessage("Id", "*") %>
        </p>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %>
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Department">Family:</label>
            <%= Html.DropDownList("Department", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%>
            <%= Html.ValidationMessage("Department", "*")%>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

但是,发布到控制器的Person对象有没有部门而且失败!

public class PersonController : Controller
{
    ...

    //
    // POST: /Person/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person Model)
    {
        try
        {
            db.AddToPerson(Model);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
    ...
}

为什么从DropDownList“Department”中选择的部门不会自动添加到模型Person?

如何将ADO.NET实体框架和ASP.NET MVC与强类型视图和控制器一起使用?

3 个答案:

答案 0 :(得分:5)

我将尝试引导您从MVC方面,因为这是问题所在,我相信

在Create()方法中,您可以从数据库中创建Person对象和Departments列表,然后将这两个对象传递给View。 View从Department列表中获取数据并使用它来呈现HTML表单 - 仅使用Id和Name。

在下一步中,表单作为值 - 密钥对的集合(标准POST)提交给服务器。路由引擎从action属性获取请求的url并将其解析为PersonController.Create(Person Model)操作。此方法的参数是Person,因此数据绑定器启动,创建Person类的新实例,并尝试将传入数据与Person的属性进行匹配。在Department的情况下,传入的值是部门的Id(因为这是您设置为DropDownList的值成员),而Person类的属性Department可能是Department类型。这是一个不匹配,所以它不能填充属性,它是空的。

正如您所看到的,这不是DropDownList的限制,问题是您无法将所有Department数据传递给DropDownList并在保存期间重新创建它(就像使用Person一样),因为POST请求的性质,这就是为什么DropDownList只从每个部门(值和名称)中获取两个值。

我通常的解决方案:通常我的模型与我的业务对象不是同一类,我通过在模型上有两个属性来实现:只获取IEnumerable属性和另一个DepartmentId属性(get / set)。然后我像这样使用它:

<%= Html.DropDownList("DepartmentId", Model.Departments) %>

然后在保存操作中,我使用DepartmentId从数据库中获取部门,将其分配给Person并保存。

在你的情况下(模型是业务对象)我可能不会尝试自动将Department绑定到Person模型,而只是抓住Id并自己完成。

这只是一个猜测(我不是EF专家),但我认为你可能还有另一个问题:如果db是Controller上的一个字段,并且在每次请求时重新创建它,这可能是一些不必要的高架。我希望它不会每次都打开数据库连接,请检查它。

希望有所帮助

答案 1 :(得分:3)

我使用ViewModel(查看NerdDinner教程,底部的参考资料)。

首先,您需要通过在部分扩展模型来伪造外键约束:

public partial class Person
{
  public int DepartmentId
  {
    get
    {
      if(this.DepartmentsReference.EntityKey == null) return 0;
      else 
        return (int)this.DepartmentsReference.EntityKey.EntityKeyValues[0].Value;
    }
    set
    {
      this.DepartmentsReference.EntityKey = 
          new EntityKey("YourEntities.DepartmentSet", "Id", value);
    }
  }
}

其次,创建ViewModel:

public class PersonFormViewModel
{
  public SelectList Departments { get; set: }
  public Person Pers { get; set; }

  public PersonFormViewModel(Person p, List<Department> departments)
  {
    this.Pers = p;
    this.Departments = new SelectList(departments, "Id", "Name", p.DepartmentId);
  }
}

第三,控制器动作(缩写创建示例):

public ActionResult Create()
{
  YourEntities entities = new YourEntities();
  List<Department> departments = entities.DepartmentSet.ToList();
  PersonFormViewModel viewModel = 
    new PersonFormViewModel(new Person(), departments);
  return View(modelView);
}    

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="Id")]Person personToCreate
{
  YourEntities entities = new YourEntities(); // Probably not instantiated here
  entities.AddToPersonSet(personToCreate);
  entities.SaveChanges();
  redirectToAction("Index");
}

第四,视图片段:

<p>
  <label for="Name">Name:</label>
  <%= Html.TextBox("Name", Model.Pers.Name) %>
  <%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
  <label for="DepartmentId">Family:</label>
  <%= Html.DropDownList("DepartmentId", Model.Departments)%>
  <%= Html.ValidationMessage("DepartmentId", "*")%>
</p>

<强>参考文献:

答案 2 :(得分:2)

我还没有发现开箱即用的DropDownList助手在模型绑定方面效果很好。我总是必须从ViewData中获取DropDownList的值,并在将更改提交到存储库或数据库之前在我的控制器中手动映射该值。

大多数时候我使用DropDownList来显示自定义类型关系的选项(例如Person的Departments)。 MVC无法简单地根据列表中所选项的值来了解如何映射对象。相反,您必须使用所选值获取该实体并自行映射。我不知道这是不是问题,我还没有尝试将模型绑定到模型只是简单类型作为选项(例如要购买的产品数量或类似的东西),但我很好奇了解有关此特定问题的更多信息以及其他人如何使用下拉列表管理模型绑定。