2009-05-21 19 views
12

Estoy utilizando ASP.NET MVC y ADO.NET Entity Framework juntos.Entity Framework con MVC fuertemente tipado

Quiero que mis Vistas y Controladores estén fuertemente tipados.

Pero, ¿cómo se supone que debo manejar las asociaciones de entidades?

Aquí está un ejemplo sencillo:

una persona tiene un departamento. Un departamento tiene cero o más personas.

Entity Data Model of Person and Department entities

Mi controlador pasa a una instancia de un objeto Person y una colección de todos los objetos del Departamento a la vista.

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

Mi View tiene un DropDownList "Departamento" con todos los departamentos como opciones.

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

<% } %> 

embargo, el objeto Persona publicado en el controlador tiene ningún Departamento y falla!

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

¿Por qué no es el departamento seleccionado de DropDownList "Departamento" añade automáticamente a la persona modelo?

¿Cómo utilizo ADO.NET Entity Framework y ASP.NET MVC con vistas y controladores fuertemente tipados?

+0

http://stackoverflow.com/questions/922402/strongly-typed-asp-net-mvc-with -ado-net-entity-framework –

Respuesta

2

No he encontrado que el complemento listo para usar DropDownList funcione muy bien con el enlace de modelo. Siempre tengo que tomar el valor de una DropDownList fuera de ViewData y asignar el valor manualmente en mi controlador antes de confirmar los cambios en el repositorio o db.

La mayoría de las veces estoy usando DropDownList para mostrar las opciones para una relación de tipo personalizado (como departamentos para una persona). MVC no puede saber cómo asignar un objeto simplemente basándose en el valor de un elemento seleccionado en una lista. Por el contrario, tiene que ir a agarrar esa entidad utilizando el valor seleccionado y asignarlo usted mismo. No sé si ese es el problema aquí, y no he intentado encuadernar una lista a un modelo con tipos simples como opciones (como cantidad de productos para comprar o algo así), pero sería curioso. para saber más sobre este problema en particular y cómo otros están administrando el enlace del modelo con listas desplegables.

+0

No creo que su problema esté aislado con el uso de EF con MVC. Tengo el mismo problema al usar POCOs. – nkirkes

5

Voy a tratar de guiarlo desde el lado MVC, ya que es donde está el problema, creo

En el método Create() se crea el objeto Person y la lista de los Departamentos de la base de datos, a continuación, ambos objetos se pasan a la Vista. La Vista toma los datos de la lista del Departamento y los utiliza para generar un formulario HTML, utilizando solo Id y Nombre.

En el siguiente paso, el formulario se envía al servidor como una colección de pares de valor clave (POST estándar). El motor de enrutamiento toma la URL solicitada del atributo de acción y la resuelve en la acción PersonController.Create (Person Model). El argumento de este método es Persona, por lo que el archivador de datos se activa, crea la nueva instancia de la clase Persona e intenta hacer coincidir los datos entrantes con las propiedades de la Persona. En el caso del Departamento, el valor entrante es Id del departamento (porque esto es lo que establece como un miembro de valor para DropDownList), mientras que el Departamento de propiedad en la clase Persona es probablemente del tipo Departamento. Esto no coincide, por lo que no puede llenar la propiedad y se deja en blanco. Como puede ver, esta no es la limitación de DropDownList, el problema es que no puede pasar todos los datos del Departamento a la DropDownList y recrearlos durante el guardado (como con la Persona), debido a una naturaleza del POST solicitud, y es por eso que DropDownList toma solo dos valores de cada departamento (valor y nombre).

Mi solución habitual: como normalmente mis modelos no son las mismas clases que mis objetos comerciales, lo hago teniendo dos propiedades en el modelo: obtengo solo la propiedad IEnumerable y otra propiedad DepartmentId (get/set). A continuación, lo uso como esto:

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

Luego, en la acción de guardar, me agarra el Departamento de la db usando DepartmentID, asignarlo a persona y guardar.

En su caso (los modelos son objetos de negocios) probablemente no intente vincular el Departamento al modelo de Persona de forma automática, sino que simplemente tome el Id y lo haga por mi cuenta.

Esto es sólo una suposición (no soy un especialista en EF), pero creo que puede haber otro problema aquí: si el db es un campo en el controlador, y se recrea en cada solicitud, esto puede ser un poco sobrecarga innecesaria. Espero que no abra una conexión db todo el tiempo, por favor verifíquelo.

Espero que ayude

3

uso un modelo de vista (echa un vistazo al tutorial NerdDinner, referencias al final).

En primer lugar, es necesario fingir una restricción de clave externa mediante la extensión de su modelo en una parcial:

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

En segundo lugar, crear el modelo de vista:

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

En tercer lugar, la acción del controlador (un abreviado crear ejemplo):

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

cuarto lugar, la vista de fragmentos:

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

Referencias:

+0

Debería haber una manera más fácil. ¿MVC 2 tiene una solución para eso? Imagine que está creando una clave externa falsa para cada ID externo, como DeparmentId. Nuestro código se vuelve un poco desordenado. :-( –

Cuestiones relacionadas