2009-05-21 121 views
12

我一起使用ASP.NET MVC和ADO.NET实体框架。实体框架与强类型MVC

我希望我的视图和控制器强类型。

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

下面是一个简单的例子:

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

Entity Data Model of Person and Department entities

我的控制器通过一个Person对象的实例,所有的部门对象的视图的集合。

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中选定的部门“部门”自动添加到模型的人吗?

如何在强类型的视图和控制器中使用ADO.NET实体框架和ASP.NET MVC?

+0

http://stackoverflow.com/questions/922402/strongly-typed-asp-net-mvc-with -ado-net-entity-framework – 2009-05-28 18:13:50

回答

2

我还没有发现开箱即用的DropDownList帮助器与模型绑定非常协调。我始终必须从ViewData中获取DropDownList的值,并在将更改提交到存储库或数据库之前,手动将值映射到我的控制器中。

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

+0

我不认为你的问题是孤立的使用EF与MVC。我有使用POCO的相同问题。 – nkirkes 2009-05-21 22:13:35

5

我会尽力引导你从MVC的一面,这就是问题的所在,我相信

在创建Person对象和部门从数据库列表中的Create()方法,然后这两个对象都被传递给View。视图从Department列表中获取数据并使用它来呈现HTML表单 - 仅使用Id和Name。

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

正如您所看到的,这不是DropDownList的限制,问题在于您无法将所有Department数据传递给DropDownList,并且在保存过程中(如使用Person)重新创建它,这是由于POST的性质请求,这就是为什么DropDownList仅从每个部门(值和名称)获取两个值的原因。我通常的解决方案是:通常我的模型与我的业务对象不同,我通过在模型上具有两个属性来完成此操作:只获取IEnumerable属性和另一个DepartmentId属性(get/set)。然后我用这样的:

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

然后在攒动,我从DB使用DepartmentID的抢部,将其分配给个人和保存。

在你的情况下(模型是业务对象),我可能不会尝试自动将部门绑定到人员模型,但只需获取Id并自行完成。

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

希望帮助

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); 
    } 
    } 
} 

二,创建视图模型:

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> 

参考文献:

+0

应该有一个更简单的方法。 MVC 2是否有解决方案?想象一下,你为每个外部id像DeparmentId创建一个假外键。我们的代码变得有点混乱。 :-( – 2010-02-23 17:30:47