2009-05-21 6 views
12

J'utilise ASP.NET MVC et ADO.NET Entity Framework ensemble.Entity Framework avec MVC fortement typé

Je veux que mes vues et contrôleurs soient fortement typés. Mais comment suis-je supposé gérer les associations d'entités?

Voici un exemple simple:

Une personne a un ministère. Un département a zéro ou plus de personnes.

Entity Data Model of Person and Department entities

Mon contrôleur passe une instance d'un objet Personne et une collection de tous les objets Département à la vue.

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

Ma vue a un DropDownList "Département" avec tous les départements comme options.

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

<% } %> 

Mais, l'objet Personne affichée sur le contrôleur n'a pas Département et échoue!

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

Pourquoi pas le département sélectionné de DropDownList « Département » automatiquement ajouté à la personne de modèle? Comment puis-je utiliser ADO.NET Entity Framework et ASP.NET MVC avec des vues et des contrôleurs fortement typés?

+0

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

Répondre

2

Je n'ai pas trouvé que l'utilitaire DropDownList prêt à l'emploi fonctionne très bien avec la liaison de modèle. Je dois toujours récupérer la valeur d'un DropDownList à partir de ViewData et mapper la valeur manuellement dans mon contrôleur avant de valider les modifications apportées au référentiel ou à la base de données.

La plupart du temps, j'utilise DropDownList pour afficher les options d'une relation de type personnalisée (par exemple, Départements pour une personne). MVC ne peut pas savoir comment mapper un objet simplement en fonction de la valeur d'un élément sélectionné dans une liste. Au contraire, vous devez aller chercher cette entité en utilisant la valeur sélectionnée et la cartographier vous-même. Je ne sais pas si c'est le problème ici, et je n'ai pas essayé de lier une liste à un modèle avec des types simples comme des options (comme la quantité de produits à acheter ou quelque chose comme ça), mais je serais curieux Pour en savoir plus sur ce problème particulier et comment les autres gèrent la liaison de modèle avec des listes déroulantes.

+0

Je ne pense pas que votre problème soit isolé d'utiliser EF avec MVC. J'ai le même problème en utilisant POCOs. – nkirkes

5

Je vais essayer de vous guider à partir du côté MVC, car c'est là le problème, je crois

Dans la méthode Create() vous créez l'objet Personne et la liste des départements de la base de données, les deux objets sont passés à la vue. La vue prend les données de la liste Département et l'utilise pour afficher un formulaire HTML - en utilisant uniquement l'identifiant et le nom. A l'étape suivante, le formulaire est soumis au serveur sous la forme d'une collection de paires valeur-clé (POST standard). Le moteur de routage extrait l'URL demandée de l'attribut action et le résout en action PersonController.Create (Person Model). L'argument de cette méthode est Person, de sorte que le classeur de données entre en jeu, crée la nouvelle instance de la classe Person et essaie de faire correspondre les données entrantes avec les propriétés de la personne. Dans le cas d'un département, la valeur entrante est l'ID du département (parce que c'est ce que vous avez défini comme membre de valeur pour DropDownList), alors que le département de propriété de la classe Person est probablement de type Department. Ceci est une discordance, donc il ne peut pas remplir la propriété et il est laissé vide.Comme vous pouvez le voir, ce n'est pas la limitation de DropDownList, le problème est que vous ne pouvez pas passer toutes les données du département à DropDownList et le recréer pendant save (comme avec la personne), en raison de la nature du POST demande, et c'est pourquoi DropDownList ne prend que deux valeurs de chaque département (valeur et nom).

Ma solution habituelle: comme normalement mes modèles ne sont pas les mêmes classes que mes objets métier, je le fais en ayant deux propriétés sur le modèle: obtenir uniquement la propriété IEnumerable et une autre propriété DepartmentId (get/set). Ensuite, je l'utilise comme ceci:

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

Puis dans la sauvegarde l'action, je prends le Département de la DB en utilisant departmentId, l'assigner à personne et enregistrer.

Dans votre cas (les modèles étant des objets métier), je n'essaierais probablement pas de lier automatiquement le département au modèle Person, mais saisissez simplement l'ID et faites-le moi-même. Ceci est juste une supposition (je ne suis pas un spécialiste EF), mais je pense que vous pouvez avoir un autre problème ici: si le db est un champ sur le contrôleur, et il est recréé à chaque demande, cela peut être un peu frais généraux inutiles. J'espère qu'il n'ouvre pas une connexion db à chaque fois, s'il vous plaît vérifiez-le.

espoir qui aide

3

J'utilise un ViewModel (consulter le tutoriel NerdDinner, les références en bas).

D'abord, vous devez simuler une contrainte de clé étrangère en étendant votre modèle dans une partielle:

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

Ensuite, créez le ViewModel:

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 troisième lieu, l'action du contrôleur (un abrégé créer par exemple):

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

Quatrièmement, l'extrait de vue:

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

Références:

+0

Il devrait y avoir un moyen plus facile. Est-ce que MVC 2 a une solution pour cela? Imaginez que vous créez une fausse clé étrangère pour chaque ID externe comme DeparmentId. Notre code devient un peu encombré. :-( –

Questions connexes