MVC Viewmodel et Entity Framework requêtes
Je suis nouveau à la fois MVC et Entity Framework et j'ai une question sur le droit/le moyen privilégié pour ce faire.
J'ai une sorte d'été à la suite de la Nerd Dîner application MVC pour la façon dont je suis en train d'écrire cette application. J'ai une page qui contient des données à partir de différents endroits. Il montre les détails qui viennent d'un peu de tables différentes et dispose également d'une liste déroulante à partir d'une table de recherche.
J'ai créé une classe ViewModel qui contient toutes ces informations:
class DetailsViewModel {
public List<Foo> DropdownListData { get; set; }
//comes from table 1
public string Property1 { get; set; }
public string Property2 { get; set; }
public Bar SomeBarObject { get; set; } //comes from table 2
}
Dans le Nerd Dîner code, leur exemple est un peu trop simpliste. Le DinnerFormViewModel prend en une seule entité: le Dîner. Basé sur le Dîner, il crée un SelectList pour le pays, basé sur le dîners emplacement.
En raison de la simplicité, leur code d'accès aux données est également assez simple. Il a un simple DinnerRepository avec une méthode appelée GetDinner(). Dans ses méthodes d'action, il peut faire des choses simples comme:
Dinner dinner = new Dinner();
//return the view model
return View(new DinnerFormViewModel(dinner));
OU
Dinner dinner = repository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
Ma requête est beaucoup plus complexe que cela, en tirant à partir de plusieurs tables...la création d'un type anonyme:
var query = from a in ctx.Table1
where a.Id == id
select new { a.Property1, a.Property2, a.Foo, a.Bar };
Ma question est comme suit:
Que dois-je référentiel de la classe ressembler? Si le référentiel de retour en classe le ViewModel lui-même? Qui ne semble pas être la bonne façon de faire les choses, depuis le ViewModel genre de implique qu'il est utilisé dans une vue. Depuis ma requête retourne un objet anonyme, comment puis-je retourner que, de mon référentiel afin que je puisse construire le ViewModel dans mes actions de contrôleur?
- +1 pour la question, je me demandais moi-même. Ont seulement joué avec MVC; n'ai pas eu l'occasion de les utiliser dans n'importe quel réel, la capacité de l'entreprise encore. Et malheureusement, vous ne pouvez pas retourner anonyme types de méthodes. (stackoverflow.com/questions/2400508/...)
Vous devez vous connecter pour publier un commentaire.
Vous êtes juste un référentiel ne doit pas renvoyer un modèle de vue. Comme les modifications apportées à votre vue va vous amener à changer votre couche de données.
Votre dépôt doit être un racine d'agrégat. Si votre propriété1, propriété2, Foo, Bar sont liés d'une certaine façon, je voudrais extraire une nouvelle classe pour gérer cela.
Si Foo et Bar ne sont pas liées à tout cela pourrait être une option à proposer un service de composer votre FooBarDetails.
où
GetFooBar(int)
ressemblerait à quelque chose comme ceci:Tout cela est une conjecture, depuis la conception du dépôt dépend vraiment de votre domaine. À l'aide de termes génériques rend difficile à développer le potentiel des relations entre les objets.
Mis à jour
Dans le commentaire, si nous avons affaire à un agrégat de la racine d'une Commande. Un ordre aurait le OrderItem et aussi le client qui a passé la commande.
Votre repo doit retourner complètement hydraté afin d'objet.
Depuis votre commande a toutes les informations nécessaires, je voudrais passer la commande directement sur le modèle de vue.
Désormais avoir un viewmodel avec un seul point peut sembler exagéré (et il est probable qu'il sera au premier abord). Si vous avez besoin d'afficher plus d'éléments sur votre point de vue, il commence à aider.
Alors que la plupart des réponses sont bonnes, je pense qu'ils manquent un entre-deux lignes de partie de votre question.
Tout d'abord, il n'existe pas de droit à 100% de chemin à faire à ce sujet, et je ne serais pas trop accroché sur les détails du modèle exact à utiliser pour le moment. En tant que votre demande est de plus en plus développée vous allez commencer à voir ce qui fonctionne et ce qui ne l'est pas, et de trouver la meilleure façon de changer le travail pour vous et votre application. Je viens de faire changer complètement le modèle de mon Asp.Net MVC backend, principalement parce que beaucoup de conseils que j'ai trouvé ne fonctionne pas pour ce que j'essayais de faire.
Cela étant dit, regardez vos couches par ce qu'ils sont censés faire. Le dépôt de la couche est destinée pour l'ajout, la suppression et la et la modification des données à partir de votre source de données. Il ne sait pas comment les données seront utilisées, et franchement, il s'en fout. Par conséquent, ils devraient juste retour de votre EF entités.
La partie de votre question, que d'autres semblent avoir disparu, c'est que vous avez besoin d'une couche supplémentaire entre vos contrôleurs et les dépôts, généralement appelé le service de la couche ou la couche de gestion. Cette couche contient les différentes classes (mais que vous souhaitez les organiser) qui appelés par les contrôleurs. Chacune de ces classes sera appel le référentiel pour récupérer les données souhaitées, puis de les convertir dans les modèles de vue que vos contrôleurs d'.
Ce service/de la couche de gestion est l'endroit où votre entreprise de logique (et si vous pensez à ce sujet, la conversion d'une entité dans un modèle de vue est logique d'entreprise, comme c'est de définir comment votre application se passe réellement à l'utilisation des données). Cela signifie que vous n'avez pas à appeler spécifiques méthodes de conversion ou de quoi que ce soit. L'idée est de dire à votre service/entreprise de la couche de ce que vous voulez faire, et il vous donne des entités commerciales (voir les modèles) à l'arrière, avec vos contrôleurs n'ayant aucune connaissance de la base de données de la structure ou de la façon dont les données ont été récupérées.
La couche de service devrait être la seule couche qui appelle les classes de dépôt ainsi.
ProductService
, mais au lieu de simplement retourner_repository.ListProducts()
vous convertirListProducts()
dans un modèle d'affichage et de retour que.Référentiel doit travailler uniquement avec les modèles types anonymes et il ne doit mettre en œuvre les opérations CRUD. Si vous avez besoin d'un filtrage, vous pouvez ajouter une couche de service pour que.
Pour le mappage entre les ViewModels et de Modèles, vous pouvez utiliser la cartographie des bibliothèques, comme Automapper.
L'actuel réponses sont très bons. Je voudrais juste faire remarquer que vous abusez les types anonymes; ils doivent seulement être utilisés pour les transports intermédiaires étapes, et ne sont jamais passés à d'autres endroits dans votre code (par exemple le modèle de vue des constructeurs).
Mon approche serait d'injecter le modèle de vue avec toutes les classes du modèle. E. g. une méthode d'action pourrait ressembler à:
J'ai le même doute de l'affiche et je ne suis toujours pas convaincu. Personnellement, je n'aime pas beaucoup les conseils de limiter le référentiel pour l'exécution de base des opérations CRUD. À mon humble avis, les performances devraient toujours être tenus en compte lors du développement d'une application réelle, et la substitution d'une jointure externe SQL avec deux requêtes différentes pour maître-détail des relations n'a pas l'air trop bonne pour moi.
Aussi, de cette façon, le principe que seuls les champs nécessaires doivent être interrogées est complètement perdu: en utilisant cette approche, nous sommes obligés de toujours récupérer tous les champs de toutes les tables concernées, ce qui est tout simplement fou dans la non-jouet applications!