Il y a des centaines de questions similaires sur ce sujet. Mais je suis toujours confus et j'aimerais obtenir des conseils d'experts à ce sujet.
Nous développons une application utilisant ASP.NET MVC 4 et EF5 et la nôtre est la première approche DB.
Nous avons une couche de données dans un projet distinct qui est une bibliothèque de classes et contient toutes les entités définies dans celui-ci. Et puis Business Layer défini avec tous les référentiels et modèles de domaine (est-ce le bon terme à utiliser). Et puis vient la couche de présentation.
À l'heure actuelle, nous n'avons défini aucun modèle de vue, nous utilisons les mêmes modèles de domaine de BL que les modèles de vue. Dans cette approche, une cartographie peut suffire.
ENTITY <=> MODEL DOMAIN
Mais pour moi, cela ne ressemble pas à un bon design. Je préfère avoir des modèles de vue définis dans ma couche de présentation et utiliser des modèles de domaine pour communiquer entre la couche de présentation et la couche métier. Et chez BL, convertissez les objets de domaine en entités de données et communiquez avec DAL. En utilisant cette approche, je dois utiliser la cartographie deux fois.
Afficher le modèle <=> MODÈLE DE DOMAINE <=> ENTITY
Mon modèle de domaine est-il vraiment nécessaire? Je ne peux pas utiliser mon entité pour communiquer avec la couche Présentation. Y a-t-il des impacts si je fais référence à des entités dans ma couche de présentation? S'il y a quel genre d'impacts?
Je pense que vous avez juste des problèmes avec la définition de chaque couche et le rôle qu'elle joue dans votre solution.
Votre niveau de données est simplement votre base de données/liste SharePoint/fichier .csv/feuille Excel ... vous avez l'idée, c'est simplement où vos données sont stockées, et elles peuvent être dans n'importe quel format. N'oubliez donc pas que le niveau de données n'est rien de plus que des données.
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
Cette couche résume votre source de données et fournit une API dans laquelle le reste de votre application peut interagir avec la source de données.
Considérez que notre source de données est une base de données MS SQL et que nous utilisons Entity Framework pour accéder aux données. Ce que vous allez essayer d'abstraire, c'est la base de données et Entity Framework, et avoir un Data Repository
pour chaque Entity
.
Nous avons une table Customers
dans une base de données MS SQL. Chaque client de la table clients est un Entity
et est représenté comme tel dans votre code C #.
En utilisant le modèle de référentiel, nous pouvons abstraire la mise en œuvre du code d'accès aux données, de sorte qu'à l'avenir, si notre source de données change, le reste de notre application ne sera pas affecté. Ensuite, nous aurions besoin d'un CustomersRepository
dans notre Data Access Layer
, qui inclurait des méthodes telles que Add
, Remove
et FindById
. Pour retirer tout code d'accès aux données. L'exemple ci-dessous montre comment vous pourriez y parvenir.
public interface IEntity
{
int Id { get; set; }
}
public class Customer : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime RegistrationDate { get; set; }
}
public interface IRepository<TEntity> where TEntity : class, IEntity
{
TEntity FindById(int id);
void Add(TEntity entity);
void Remove(TEntity entity);
}
public class CustomerRepository : IRepository<Customer>
{
public Customer FindById(int id)
{
// find the customer using their id
return null;
}
public void Add(Customer customer)
{
// add the specified customer to the db
}
public void Remove(Customer customer)
{
// remove the specified customer from the db
}
}
La couche d'accès aux données appartient entre la couche de données et la logique métier.
// ----------------------------
// Business logic
// ----------------------------
// ----------------------------
// Data access layer
// - Repository
// - Domain models / Business models / Entities
// ----------------------------
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
La couche métier est construite au-dessus de la couche d'accès aux données et ne traite pas des problèmes d'accès aux données, mais strictement de la logique métier. Si l'une des exigences commerciales était d'empêcher que des commandes soient passées de l'extérieur du Royaume-Uni, la couche de logique commerciale s'en occuperait.
Le niveau de présentation présente simplement vos données, mais si vous ne faites pas attention aux données que vous présentez et aux données que vous autorisez à publier, vous vous préparerez à de nombreux maux de tête sur toute la ligne, c'est pourquoi il est Il est important d'utiliser des modèles de vue, car les modèles de vue sont une préoccupation de niveau de présentation, le niveau de présentation n'a pas besoin de connaître quoi que ce soit sur vos modèles de domaine, il a seulement besoin de connaître les modèles de vue.
Alors, que sont les modèles de vue ... Ce sont simplement des modèles de données qui sont adaptés à chaque vue, par exemple, un formulaire d'inscription comprendrait un RegistrationViewModel
, exposant ces propriétés typiques.
public class RegistrationViewModel
{
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
Le niveau de présentation gère également la validation des entrées, par exemple pour valider si une adresse e-mail saisie a le format correct ou si la correspondance des mots de passe est une préoccupation de niveau de présentation, pas une préoccupation commerciale, et peut être gérée à l'aide de Data Annotations
.
public class RegistrationViewModel
{
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Compare("ConfirmPassword")
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
La raison pour laquelle il est important d'utiliser les modèles de vue est que les modèles commerciaux appartiennent à la couche métier et qu'ils incluent des données qui doivent rester privées. Par exemple, si vous deviez exposer le modèle de domaine dans une réponse JSON, cela exposerait les données complètes des utilisateurs, leur nom et leur adresse, car vous n'êtes pas sélectif sur ce qui est exposé et ce qui ne l'est pas, mais utilisez tout ce qui semble fonctionner.
Je dois également souligner ici qu'il existe une différence entre domain models
et entity models
. Il y a déjà une réponse qui va beaucoup plus en détail ici
Je vais garder ce bref:
Je ne suis pas un expert, mais je partagerai mes 50 cents sur le sujet.
Je voudrais partager votre inquiétude concernant l'ignorance du modèle d'affichage.
En utilisant le modèle de vue, vous pouvez:
Donc, je considère également que c'est une mauvaise conception, mais d'autres pourraient avoir une opinion différente.
N'oubliez pas que la couche métier ne sait rien du modèle de vue, vous devez donc le mapper dans le contrôleur.
Je commencerais simplement, en utilisant un POCO comme modèle de domaine qui peut être conservé avec un ORM ou un NoRM. Pour la plupart des logiciels développés dans le monde, cela n'endommagera pas beaucoup votre système et c'est aussi simple.
À l'avenir, si vous commencez à utiliser les services Web pour une raison quelconque, vous devrez peut-être envisager l'utilisation de DTO (Data Transfer Objects) pour les appels distants. Une fois sur place, ce que vous pouvez faire est d'avoir une autre couche, responsable de la mise en correspondance de votre modèle de domaine avec le DTO souhaité. Cette couche ne serait utilisée que dans l'appel distant (service Web), en conservant le modèle d'affichage pour la présentation.
Le principal avantage de l'introduction de classes supplémentaires est la séparation des préoccupations:
Cela peut être réalisé avec seulement deux classes de modèle pour ViewModels et les entités de domaine. Au lieu de modéliser la logique du domaine avec des classes de modèle distinctes similaires aux entités persistantes, implémentez-la dans les classes de service qui consomment les entités de domaine. Les entités de domaine doivent tout au plus avoir une logique qui traite de leurs propres propriétés (par exemple, pour conserver les valeurs combinées de deux propriétés dans un état valide). Si plusieurs entités de domaine sont affectées par un cas d'utilisation, modélisez ce cas d'utilisation dans une classe de service. Si vous mettez de la logique pour gérer la relation entre les entités directement dans les classes d'entités, le code devient ingérable très rapidement (croyez-moi, j'ai essayé).
Je ne recommande pas d'utiliser les entités persistantes comme ViewModels, car cela mélangerait les problèmes d'affichage (par exemple [DisplayName]
) avec des problèmes de persistance (par exemple [ForeignKey]
).