Strongly typed ASP.NET MVC with ADO.NET Entity Framework

I finally got this job after several days of struggle.

I have a simple database of people and departments:

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

I can use strongly typed ASP.NET MVC views for link / navigation properties! See the list of departments ...

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

Part of my face / Edit view:

<% 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> <% } %> 

Part of my Person controller:

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

To get this working, I extended the Person EntityObject with the new DepartmentId property.

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

And I expanded the ObjectContext of the Entity Framework object with the new AttachUpdated and ApplyReferencePropertyChanges methods:

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

I just wanted to document my progress here. Please suggest improvements.




Thank:

+13
asp.net-mvc entity-framework
May 28 '09 at 18:12
source share
2 answers

I started working with ASP.NET MVC, so I came across this thread, so I'm not sure if you are still checking for improvements.

I do not like the idea of ​​adding a new property to an incomplete class in the entity infrastructure, because it does not allow so many changes. Try tagging your Deppment DropDown "Department.Id" like this

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

The ModelBinding for the MVC Framework will pick up the value and apply it to the "Id" property of the Department navigation property. I found that other Department values ​​are null, but that is not significant. Now you have a way to get the right department and apply it to the navigation property of the department of the new Person object created in the Model Link parameter with your Action parameter, for example:

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

Thus, you do not need to update your Entity at all for the property that it should have.

+8
Sep 22 '09 at 2:22
source share

Improve your edit control so that it handles exceptions that have been thrown and re-displays user input. I'm sure you were going to;)

Refresh your view to have validators:

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

and then use them in your edit:

 [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
May 28 '09 at 18:58
source share



All Articles