2009-05-28 12 views
13

Finalmente he conseguido que esto funcione después de días de lucha.Very-Typed ASP.NET MVC con ADO.NET Entity Framework

Tengo una base de datos simple de las personas y departamentos:

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

puedo usar vistas inflexible de ASP.NET MVC para las propiedades de referencia/de navegación! Ver la lista de departamentos ...

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

Parte de mi opinión de la persona/Editar:

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

Parte de mi controlador de Persona:

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

Para conseguir este trabajo, Extendí Person EntityObject con una nueva propiedad DepartmentId.

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

Y extendió el Entity Framework ObjectContext con nuevos métodos y 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; 
      } 
     } 
    } 

} 

sólo quería documentar mi progreso aquí. Por favor sugiere mejoras


Gracias:

+3

Buen trabajo, pero desafortunadamente stackoverflow.com no es el lugar para documentar su progreso. He votado para cerrar: "no es una pregunta real". –

+1

¿No necesita excluir la propiedad de ID cuando vincula el objeto persona aquí: public ActionResult Edit (ID de guía, modelo de persona)? –

+3

Ah, me perdí la parte de "sugerir mejoras". Déjalo vivir, digo. –

Respuesta

8

he empezado a trabajar con ASP .NET MVC, por lo que me encontré con este hilo, por lo que no estoy seguro de si aún está buscando mejoras.

No me gusta la idea de agregar la nueva propiedad a una clase parcial en el marco de entidad porque no permite tanto cambio. Trate de etiquetar su Departamento "DropDown" del departamento.Id" como esto

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

El ModelBinding de la MVC Framework recogerá el valor y aplicarlo a la 'id' Propiedad del 'Departamento' navegación por la propiedad. Lo que he encontrado es que los otros valores del Departamento son null, pero eso no es significativo. Ahora tiene una forma de recuperar la entidad de departamento correcta y aplicarla a la propiedad de navegación de departamento de la nueva entidad de persona creada en el parámetro vincular a su acción, algo como:

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

Al hacerlo de esta manera, no necesita actualizar su Entidad en absoluto para una propiedad que debería tener.

+1

¡bueno y limpio! Zack, también podría establecer EntityKey en sus controladores. Método de edición: newPerson.DepartmentReference.EntityKey = new EntityKey ("YourEntities.Department", "DepartmentId", int.Parse (Request.Form ["DepartmentId"])); –

0

Mejora tu Editar controlar para que maneje las excepciones que se tiran y vuelve a mostrar la entrada del usuario ha escrito en la medida. Estoy seguro de que estaban a punto;)

actualización de su punto de vista para tener validadores:

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

y luego utilizarlos en su edición:

[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

"'.... La persona' no contiene una definición de 'Errores' y no se encontraron 'Errores' aceptando un primer argumento de tipo '.... Persona' (¿falta una directiva de uso o una referencia de ensamblaje?) " –

+0

Depende de qué marco esté utilizando. Lightspeed y Linq2Sql le otorgan la propiedad Errors en cada entidad. Si está compilando sus Entidades de forma manual en lugar de utilizar un ORM, necesitará construir esa propiedad en su clase parcial para Persona. – womp

+0

Algo como el Listado 3 y 4 en este artículo: http://www.asp.net/Learn/mvc/tutorial-16-cs.aspx – womp

Cuestiones relacionadas