Confusion sur l’endroit où placer la logique métier lors de l’utilisation du framework d’entité

Je viens de commencer à travailler avec le framework Entity et je ne comprends pas comment les classes normalement présentes dans la couche de gestion s’intègrent aux entités créées par Entity Framework.

En travaillant avec ADO.NET classique, j’aurais une classe appelée Customer par exemple, puis une autre classe appelée DALCustomer pour gérer l’interaction de la firebase database. Dans cette structure, j’aurais mis le code pour effectuer des calculs, filtrer et traiter une instance Client pour l’enregistrement, la mise à jour et la suppression dans la classe Client.

Avec Entity Framework, si vous avez une table appelée Customer, la structure Entity crée une entité appelée Customer et c’est là que ma confusion commence. Cette entité supprime-t-elle la nécessité d’un client dans la couche de gestion? Donc, essentiellement, tous les champs et toutes les méthodes normalement utilisés dans la couche métier vont dans l’entité générée par Entity Framework? Ou bien une classe existe-t-elle encore dans la couche de gestion appelée CustomerBL, par exemple, qui contient toujours les champs et les méthodes nécessaires pour accomplir la logique métier requirejse pour les calculs, le filtrage et une instance de la DAL EF déclarée?

S’il doit y avoir une classe métier, dans ce cas CustomerBL, une autre question se pose: les champs créés dans l’entité client doivent-ils être recréés dans CustomerBL ou une instance de l’entité Customer doit-elle être déclarée dans CustomerBL? pas besoin d’avoir les champs déclarés à 2 endroits?

Le framework d’entité, par opposition à linq-to-sql par exemple, a été conçu en gardant à l’esprit la séparation entre le modèle de données et le modèle conceptuel. Il prend en charge l’ inheritance , le fractionnement d’entités , le fractionnement de tableaux , les types complexes et les associations plusieurs-à-plusieurs transparentes , qui permettent de modeler le modèle de domaine selon ses besoins sans être trop contraint par le modèle

L’approche basée sur le code en premier permet de travailler avec des POCO dans lesquels les propriétés sélectionnées peuvent être mappées aux colonnes du magasin de données. Model-first et Database-first génèrent des classes partielles, permettant d’étendre le code généré. Travailler avec ces classes a largement l’air de travailler avec les POCO. Encore plus depuis la version 5, lorsque DbContext est devenu l’API par défaut, les classes générées n’étaient plus ObjectContext le code de persistance de l’API ObjectContext .

Bien entendu, cette séparation du modèle conceptuel et du modèle de magasin ne peut réussir que dans une certaine mesure. Certaines choses vont à l’encontre de cet objective d’ ignorance persistante . Par exemple, si un chargement différé est souhaitable, il est nécessaire de déclarer les propriétés de navigation comme virtual , de sorte que EF puisse les remplacer dans les types de proxy. Et il est très pratique d’avoir des propriétés de clé étrangère primitives (par exemple, ParentId ) accompagnant les “vraies” associations (une référence Parent ). Les puristes considèrent cela comme une violation de la conception pilotée par le domaine.

Une autre violation importante de l’ignorance de la persistance est le grand nombre de différences entre linq-to-objects et linq-to-entity . Vous ne pouvez tout simplement pas ignorer le fait que vous vous situez dans un univers totalement différent des objects en mémoire. Ceci est appelé couplage serré, ou abstraction qui fuit .

Mais alors … en général, je suis content d’utiliser des classes EF ou POCO générées à partir d’un modèle en code premier en tant que classes de domaine. Jusqu’à présent, je n’ai jamais vu une transition sans friction d’un magasin de données à un autre, si cela se produit. La persistance de l’ignorance est une fiction. Les particularités du DAL laissent toujours une empreinte dans le domaine. Ce n’est que lorsque vous devez coder pour différents magasins / modèles de données ou lorsque les magasins / modèles sont censés changer relativement souvent qu’il est avantageux de minimiser autant que possible cette empreinte ou de la supprimer complètement.

Un autre facteur est que promouvoir les classes EF en tant que classes de domaine est que de nombreuses applications ont aujourd’hui plusieurs niveaux, où différents modèles d’affichage ou DTO (sérialisés) sont envoyés à un client. L’utilisation de classes de domaine dans les interfaces utilisateur ne correspond pratiquement jamais à la facture. Vous pouvez également utiliser les classes EF en tant que domaine et faire en sorte que les services utilisent des modèles et des DTO dédiés comme requirejs par une interface utilisateur ou des consommateurs de services. Une autre couche d’abstraction peut être plus un fardeau qu’une bénédiction, si ce n’est que sur le plan de la performance.

À mon avis, le but de l’utilisation de POCO en tant qu’entités pouvant être persistantes est de supprimer la distinction entre les “entités de firebase database” et les “entités commerciales”. Les “entités” sont supposées être des “entités commerciales” qui peuvent être directement conservées et chargées à partir d’un magasin de données et, par conséquent, agir simultanément comme “entités de firebase database”. En utilisant POCO, les entités métier sont découplées du mécanisme spécifique pour interagir avec une firebase database.

Vous pouvez par exemple déplacer les entités dans un projet distinct qui ne fait référence à aucun assemblage EF et les utiliser dans un projet de couche de firebase database pour gérer la persistance.

Cela ne signifie pas que vous pouvez concevoir vos entités commerciales complètement sans avoir les exigences pour EF en tête. Vous devez connaître certaines limites pour éviter les problèmes lorsque vous devez associer les entités métier à un schéma de firebase database à l’aide d’EF, par exemple:

  • Vous devez rendre les propriétés de navigation (références ou collections de références à d’autres entités) virtual pour prendre en charge le chargement différé avec EF
  • Vous ne pouvez pas utiliser IEnumerable pour les collections à conserver. Ce doit être ICollection ou un type plus dérivé.
  • Il n’est pas facile de conserver private propriétés private
  • Le type char n’est pas supporté par EF et vous ne pouvez pas l’utiliser si vous souhaitez conserver ses valeurs
  • et plus…

À mon avis, un ensemble supplémentaire d’entités est une couche supplémentaire de complexité qui devrait être justifiée si les limitations mentionnées sont trop ssortingctes pour votre projet.

YA2C (Encore 2 cents 🙂

Je ne sais pas si cela est considéré comme une bonne pratique par d’autres, mais personnellement, c’est comme ça que j’ai géré cela par le passé:

Les classes générées par EF sont vos DAL, puis pour BL, créez un ensemble complémentaire de classes dans lesquelles vous aurez la structure requirejse (par exemple, fusionner des données d’entités associées dans une relation un-à-un) et traiter d’autres problèmes de logique métier. (validation personnalisée comme implémenter IDataErrorInfo pour le rendre agréable avec l’interface utilisateur dans WPF par exemple) et créer également des classes contenant toutes les méthodes de couche de gestion relatives à un type d’entité utilisant les instances BL et convertissant vers et depuis des entités EF aux objects BL.

Ainsi, par exemple, vous avez un client dans votre firebase database. EF générera une classe Customer, et dans le BL, il y aura une classe Customer (préfixe, suffixe, etc.) et une classe CustomerLogic. Dans la classe BL Customer, vous pouvez faire tout ce qui est nécessaire pour satisfaire aux exigences sans altérer les entités EF et dans la classe CustomerLogic, vous avez des méthodes BL (charger les clients les plus précieux, enregistrer des données supplémentaires, etc.).

Maintenant, cela vous permet d’être faiblement couplé à l’implémentation de la source de données. Un autre exemple de ce qui m’a profité par le passé (dans un projet WPF) est que vous pouvez faire des choses comme implémenter IDataErrorInfo et implémenter la logique de validation dans les classes CustomerBL pour que lorsque vous liez l’entité à un formulaire de création / modification vous bénéficierez de la fonctionnalité intégrée fournie par WPF.

… Mes 2 centimes, je suis également curieux de savoir quelle est la meilleure pratique ou quelles sont les autres solutions / points de vue.


Peut-être aussi lié à ce sujet – Code-first vs Model / Database-first

Ce sujet est peut-être un peu vieux mais cela peut aider. Andras Nemes a souligné dans son blog le souci d’utiliser DDD (conception pilotée par le domaine) sur la conception pilotée par la technologie telle que EF, MVC, etc.

http://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/

J’ai utilisé la logique métier pour écrire mes méthodes et renvoyer les résultats dans sa vue créée comme suit:

 namespace Template.BusinessLogic { public interface IApplicantBusiness { List GetAllApplicants(); void InsertApplicant(Template.Model.ApplicantView applicant); } }