2009-05-28 67 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