2009-05-28 51 views
13

经过几天的努力,我终于得到了这个工作。使用ADO.NET实体框架的强类型ASP.NET MVC

我得人和部门的一个简单的数据库:

ADO.NET Entity Framework Entity Data Model diagram with Department and Person objects http://img39.imageshack.us/img39/1368/edmxdepartmentperson.gif

我可以借鉴/导航性能强类型ASP.NET MVC的意见!见部门列表...我的人/编辑观点的

ASP.NET MVC with DropDownList http://img11.imageshack.us/img11/7619/dropdownlistdepartment.gif

部分:

<% using (Html.BeginForm()) {%> 
    <%= Html.Hidden("Id", Model.Id) %> 
    <fieldset> 
     <legend>Fields</legend> 
     <p> 
      <label for="Name">Name:</label> 
      <%= Html.TextBox("Name", Model.Name) %> 
     </p> 
     <p> 
      <label for="DepartmentId">Department:</label> 
      <%= Html.DropDownList("DepartmentId", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%> 
     </p> 
     <p> 
      <input type="submit" value="Save" /> 
     </p> 
    </fieldset> 
<% } %> 

我一个人控制器的部分:

// 
// GET: /Person/Edit/5 

public ActionResult Edit(Guid id) 
{ 
    ViewData["Departments"] = ctx.Department; 
    Person model = (from Person p in ctx.Person 
        where p.Id == id 
        select p).FirstOrDefault(); 
    return View(model); 
} 

// 
// POST: /Person/Edit 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(Person model) 
{ 
    ctx.AttachUpdated(model); //extension 
    ctx.SaveChanges(); 
    return RedirectToAction("Index"); 
} 

为了得到这个工作,我用新的DepartmentId属性扩展了Person EntityObject。

using System; 
using System.Data; 
using System.Data.Objects.DataClasses; 

namespace ProjectName.Models 
{ 
    public partial class Person : EntityObject 
    { 
     public Guid DepartmentId 
     { 
      get 
      { 
       try 
       { 
        return (Guid)this.DepartmentReference.EntityKey.EntityKeyValues[0].Value; 
       } 
       catch 
       { 
        return Guid.Empty; 
       } 
      } 
      set 
      { 
       this.DepartmentReference.EntityKey = new EntityKey("JunkEntities.Department", "Id", value); 
      } 
     } 
    } 
} 

我延长了实体框架ObjectContext的新AttachUpdated和ApplyReferencePropertyChanges方法:

using System; 
using System.Data; 
using System.Data.Objects; 
using System.Data.Objects.DataClasses; 

public static class EntityFrameworkExtensionMethods 
{ 

    public static void AttachUpdated(this ObjectContext ctx, EntityObject objectDetached) 
    { 
     if (objectDetached.EntityKey == null) 
     { 
      String entitySetName = ctx.DefaultContainerName + "." + objectDetached.GetType().Name; 
      Guid objectId = (Guid)objectDetached.GetType().GetProperty("Id").GetValue(objectDetached, null); 
      objectDetached.EntityKey = new System.Data.EntityKey(entitySetName, "Id", objectId); 
     } 
     if (objectDetached.EntityState == EntityState.Detached) 
     { 
      object currentEntityInDb = null; 
      if (ctx.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb)) 
      { 
       ctx.ApplyPropertyChanges(objectDetached.EntityKey.EntitySetName, objectDetached); 
       ctx.ApplyReferencePropertyChanges((IEntityWithRelationships)objectDetached, 
                (IEntityWithRelationships)currentEntityInDb); //extension 
      } 
      else 
      { 
       throw new ObjectNotFoundException(); 
      } 
     } 
    } 

    public static void ApplyReferencePropertyChanges(this ObjectContext ctx, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity) 
    { 
     foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds()) 
     { 
      var oldRef = relatedEnd as EntityReference; 
      if (oldRef != null) 
      { 
       var newRef = newEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference; 
       oldRef.EntityKey = newRef.EntityKey; 
      } 
     } 
    } 

} 

我只是想在这里记录我的进步。请提出改进​​建议。


感谢:

+3

不错的工作,但不幸的是stackoverflow.com在不是为你记录你的进步的地方。我投票结束:“不是一个真正的问题”。 – 2009-05-28 18:17:14

+1

在绑定person对象时,您不需要排除ID属性:public ActionResult Edit(Guid id,Person Model)? – 2009-05-28 18:22:56

+3

啊,我错过了“建议改进”的部分。让它活下去,我说。 – 2009-05-28 18:24:46

回答

8

我已经开始与ASP工作.NET MVC这就是为什么我来到这个线程,所以我不知道你是否还在检查改进。

我不喜欢将新属性添加到实体框架上的部分类的想法,因为它不允许有太多改变。 尝试标记您的Deparment DropDown“部门。ID”这样

<p> 
    <label for="Department.Id">Department:</label> 
<%= Html.DropDownList("Department.Id", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%> 
</p> 

的MVC框架的ModelBinding将拿起值,并将其应用到‘部门‘导航属性Id’的属性’。我发现的是,部门的其他值现在你有一种方法来检索正确的部门实体并将其应用到在模型绑定到你的动作参数中创建的新人物实体的部门导航属性中,如下所示:

newPerson.Department = ctx.Department.First(d => d.DepartmentId == newPerson.Department.Id); 
newPerson.Department = ctx.Department.First(d => d.DepartmentId == newPerson.Department.Id); 

通过这种方式,您不需要更新您的实体就可以拥有它应该拥有的房产。

+1

好又干净! Zack,你也可以在你的控制器上设置EntityKey编辑方法: newPerson.DepartmentReference.EntityKey = new EntityKey(“YourEntities.Department”,“DepartmentId”,int.Parse(Request.Form [“DepartmentId”])); – 2010-02-23 17:48:58

0

提高你的编辑控制,使其处理被抛出的异常并重新显示输入用户在目前输入。我敢肯定你正要;)

更新你的看法有验证:

<label for="Name">Name:</label> 
<%= Html.TextBox("Name", Model.Name) %> 
<%= Html.ValidationMessage("Name", "*") %> 

,然后利用它们在你的编辑:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(Person Model) 
{ 
    try 
    { 
     ctx.AttachUpdated(Model); //extension 
     ctx.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 
    catch 
    { 
     foreach (var err in Model.Errors) 
      ModelState.AddModelError(err.PropertyName, err.ErrorMessage) 

     return View(Model); 
    } 
} 
+0

“'....'Person'不包含'Errors'的定义并且没有扩展方法'Errors'接受类型'....'的第一个参数可以被找到(你是否缺少using指令或者组装参考?)“ – 2009-05-28 19:51:12

+0

这取决于你使用的是什么框架。 Lightspeed和Linq2Sql为您提供每个实体的错误属性。如果您手动构建实体而不是使用ORM,那么您需要将该属性构建到Person的部分类中。 – womp 2009-05-28 21:56:16

+0

像这篇文章中的清单3和4一样:http://www.asp.net/Learn/mvc/tutorial-16-cs.aspx – womp 2009-05-28 22:04:58