Je vais jeter là-bas, si vous avez besoin de se moquer de vos modèles que vous faites mal. Vos modèles devraient être des sacs de propriété muets.
Il n'y a absolument aucune raison pour que votre modèle dispose d'une méthode SendEmail. C'est une fonctionnalité qui devrait être appelée depuis un contrôleur appelant vers un EmailService.
En réponse à votre question:
Après des années de travail avec séparation des modèles de Concern (SOC) comme MVC, MVP, MVVM et de voir des articles des gens plus lumineux que moi (je voudrais pouvoir trouver celui que je Je réfléchis à ce sujet mais peut-être que je l'ai lu dans un magazine). Vous finirez par conclure dans une application d'entreprise que vous finirez avec 3 ensembles distincts d'objets de modèle.Auparavant, j'étais un très grand fan de la conception DDD (Domain Driven Design) en utilisant un seul ensemble d'entités commerciales qui étaient à la fois des objets C# plain (POCO) et Persistent Ignorant (PI). Avoir des modèles de domaine qui sont POCO/PI vous laisse avec une liste d'objets propre où il n'y a pas de code lié à l'accès au stockage d'objets ou ayant d'autres attributs qui ont une signification schématique pour seulement 1 zone du code. Bien que cela fonctionne et puisse fonctionner assez bien pendant un certain temps, il existe un point de basculement où la complexité de l'expression de la relation entre Vue, Modèle de domaine et Modèle de stockage physique devient trop complexe pour s'exprimer correctement avec 1. ensemble d'entités.
Pour résoudre les problèmes d'impédance de View, Domain et Storage, vous avez vraiment besoin de 3 jeux de modèles. Vos ViewModels correspondront exactement à vos vues pour faciliter le travail avec l'interface utilisateur. Donc, cela aura souvent des choses telles que l'ajout d'une Liste pour peupler les listes déroulantes avec des valeurs qui sont valables pour votre vue d'édition/action. Au milieu se trouvent les entités de domaine, ce sont les entités que vous devez valider par rapport à vos règles métier. Vous allez donc les mapper depuis/vers les deux côtés de la vue et depuis/vers la couche de stockage. Dans ces entités est où vous pouvez joindre votre code pour faire la validation. Personnellement, je ne suis pas fan de l'utilisation d'attributs et de la logique de validation de couplage dans vos entités de domaine. Cela fait beaucoup de sens de coupler des attributs de validation dans vos ViewModels pour tirer parti de la fonctionnalité de validation côté client MVC intégrée.
Pour la validation, je recommande d'utiliser une bibliothèque comme FluentValidation (ou votre propre custom, ils ne sont pas difficiles à écrire) qui vous permet de séparer vos règles métier de vos objets. Bien qu'avec les nouvelles fonctionnalités de MVC3, vous puissiez effectuer des validations à distance et avoir le côté client, il s'agit d'une option pour gérer la véritable validation de votre activité.
Enfin, vous avez vos modèles de stockage. Comme je l'ai dit précédemment, j'ai été très zélé pour que les objets PI puissent être réutilisés à travers toutes les couches, donc en fonction de la configuration de votre stockage durable, vous pourriez utiliser directement les objets de votre domaine. Mais si vous utilisez des outils tels que Linq2Sql, EntityFramework (EF) etc, vous aurez très probablement des modèles générés automatiquement avec du code pour interagir avec le fournisseur de données, vous aurez donc besoin de mapper vos objets de domaine à vos objets de persistance.
envelopper Alors tout cela jusqu'à ce serait un flux logique standard dans les actions MVC
utilisateur va modifier la fiche produit
EF interroge la base de données pour obtenir les informations de produit existant, à l'intérieur du couche de référentiel Les objets de données EF sont mappés sur les entités métier (BE) de sorte que toutes les méthodes de couche de données renvoient des BE et n'ont aucun couplage externe aux objets de données EF.(Ainsi, si vous changez de fournisseur de données, vous n'avez pas besoin de modifier une seule ligne de code sauf pour l'implémentation interne)
Le contrôleur obtient le produit BE et le mappe sur un Product ViewModel (VM) et ajoute collections pour les différentes options qui peuvent être définies pour les listes déroulantes
Retour Voir (theview, ProductVM)
utilisateur modifie le produit et soumet le formulaire
validation côté client est passé (utile pour la date de validation/numéro de validation au lieu d'avoir à soumettre le formulaire de rétroaction)
Le ProductVM revient mappé à ProductBE à ce stade, vous validerait les règles commerciales le long des lignes Vous passez le ProductBE dans votre modèle de référentiel, dans l'implémentation interne de la couche de données, vous associez le ProductBE à l'Entité de données de produit pour EF et si vous ne le validez pas. mettre à jour la base de données.
2016 edit: usages retirés de Interface
que la séparation des préoccupations et des interfaces sont entièrement orthogonal.
btw, un "modèle" normalement ne contient pas de logique (comme SendEmail()) – Will
N'ouvrons pas la can-de-worms qui est maigre/gros contrôleur/modèle! Où pensez-vous que SendEmail() devrait aller? – med4th