Est-ce que DTO plus UnitOfWork pattern est une bonne approche pour concevoir un DAL pour une application web?

j'implémente un DAL en utilisant entity framework. Sur notre application, nous avons trois couches (DAL, business layer et presentation). Ce est une application web. Lorsque nous avons commencé à mettre en œuvre le DAL, notre équipe a pensé que le DAL devrait avoir des classes dont les méthodes reçoivent un contexte Object donné par les services sur la couche d'affaires et d'opérer sur elle. La raison d'être de cette décision est que des contextes D'Object différents voient des États DB différents, de sorte que certaines opérations peuvent être rejetées en raison de problèmes avec des clés étrangères correspondance et autres incohérences.

nous avons remarqué que la génération et la propagation d'un contexte objet à partir de la couche services génère un couplage élevé entre les couches. C'est pourquoi nous avons décidé d'utiliser des Dto cartographiés par Automapper (pas d'entités non gérées ou d'entités auto-traceuses plaidant un couplage élevé, exposant les entités à des couches supérieures et une faible efficacité) et UnitOfWork. Voici donc mes questions:

  1. est - ce la bonne approche pour concevoir le DAL d'une application web? Pourquoi?
  2. Si vous avez répondu "oui" à 1. comment concilier le concept de DTO avec les schémas D'Unité de travail?
  3. Si vous avez répondu "non" à 1., quelle pourrait être l'approche correcte pour concevoir un DAL pour une application Web?

veuillez, si possible, fournir une bibliographie à l'appui de votre réponse.

A propos du design actuel:

le développement de l'application est prévu sur trois niveaux: présentation, business et DAL. Affaires layer A à la fois des façades et des services

il existe une interface appelée ITransaction (avec seulement deux méthodes pour disposer et enregistrer les modifications) qui n'est visible que dans les services. Pour gérer une transaction, il y a une Transaction de classe étendant un ObjectContext et ITransaction. Nous avons conçu ceci en gardant à l'esprit que chez business layer nous ne voulons pas que d'autres méthodes ObjectContext soient accessibles.

Sur le DAL, nous avons créé un dépôt abstrait en utilisant deux types génériques (un pour l'entité et l'autre pour son DTO associé). Ce dépôt dispose de méthodes CRUD mises en œuvre de manière générique et de deux méthodes génériques pour cartographier les DTO et les entités du dépôt générique avec AutoMapper. Le constructeur du dépôt abstrait prend une ITransaction comme argument et il s'attend à ce que L'ITransaction soit un ObjectContext afin de l'assigner à sa propriété proctected ObjectContext.

les dépôts en béton ne devraient recevoir et renvoyer que des types et des types de réseaux. DTOs.

nous sommes maintenant confrontés à ce problème: la méthode générique à créer ne génère pas d'id temporel ou persistant pour les entités attachées (jusqu'à ce que nous utilisions SaveChanges(), donc en brisant la transactionalité que nous voulons); cela implique que les méthodes de service ne peuvent pas l'utiliser pour associer les DTO dans le BL)

10
demandé sur JPCF 2010-12-29 17:34:16

4 réponses

Il y a un certain nombre de choses qui se passent ici...Je suppose que vous utilisez une architecture à 3 niveaux. Cela dit, Je ne suis pas clair sur quelques décisions de design que vous avez prises et quelles étaient les motivations derrière les prendre. En général, je dirais que votre ObjectContext ne devrait pas être transmis dans vos classes. Il devrait y avoir une sorte de gestionnaire ou de classe de dépôt qui gère la gestion de la connexion. Cela résout votre problème de gestion de DB state. Je trouve qu'un Référentiel modèle fonctionne vraiment bien ici. De là, vous devriez être en mesure de mettre en œuvre l'Unité de travail assez facilement puisque votre gestion de connexion sera traitée en un seul endroit. Vu ce que je sais de votre architecture, je dirais que vous devriez utiliser une stratégie de POCO. L'utilisation de POCOs ne vous lie pas étroitement à un fournisseur D'ORM. L'avantage est que vos POCOs seront capables d'interagir avec votre ObjectContext (probablement via un dépôt quelconque) et cela vous donnera une visibilité sur le suivi des modifications. Encore une fois, à partir de là, vous serez en mesure de mettre en œuvre le modèle D'Unité de travail (transaction) pour vous donner le plein contrôle sur la façon dont votre transaction d'affaires devrait se comporter. Je trouve que c'est incroyablement utile article pour expliquer comment tout cela s'imbrique. Le code est bogué, mais il illustre avec précision les meilleures pratiques pour le type d'architecture que vous décrivez: dépôt, Spécification et mise en œuvre de L'Unité de travail

La version courte de ma réponse le numéro de la question 1 est "non". Le lien ci-dessus donne ce que je crois être une meilleure approche pour vous.

6
répondu Jason 2011-01-05 16:53:11

j'ai toujours cru que le code peut mieux expliquer les choses que des mondes pour les programmeurs. Et c'est particulièrement vrai pour ce sujet. C'est pourquoi je vous suggère de regarder la grande application d'échantillon dans la sorcière tous les conseptts que vous attendez sont mis en œuvre.

alt text

le projet s'appelle Sharp Architecture, il est centré autour de MVC et NHibernate, mais vous pouvez utiliser les mêmes approches en remplaçant NHibernate pièces avec EF ceux dont vous avez besoin. Le but de ce projet est de fournir un modèle de demande avec toutes les pratiques exemplaires de la communauté pour la création d'applications web.

il couvre tous les sujets communs et la plupart des sujets peu communs lors de l'utilisation des ORMS, la gestion des transactions, la gestion des dépendances avec les conteneurs du CIO, utilisation de DTOs, etc.

Et voici un exemple d'application.

j'insiste pour lire et essayer, ce sera avec un réel trasure pour vous comme pour moi.

4
répondu Restuta 2015-08-06 18:51:52

Vous devriez jeter un oeil injection de dépendances et l'inversion de contrôle signifie en général. Cela permettrait de contrôler le cycle de vie de ObjectContext "de l'extérieur". Vous pouvez vous assurer qu'une seule instance de contexte objet est utilisée pour chaque requête http. Pour éviter de gérer les dépendances manuellement, je recommande d'utiliser StructureMap comme un conteneur.

ObjectContext directement, vous utiliseriez ainsi appelé Dépôt qui est responsable de fournir la collecte comme L'API pour votre magasin de données. Cet outil couture que vous pouvez utiliser pour commuter le mécanisme de stockage de données sous-jacent ou pour simuler la persistance complètement pour les tests.

comme Jason l'a déjà suggéré - vous devriez aussi utiliser POCO's (vieux objets clr). Malgré cela, il y aurait encore un couplage implicite avec entity framework vous devriez être conscient de, c'est beaucoup mieux que d'utiliser des classes générées.

Choses que Vous ne pourriez pas trouver ailleurs assez vite:

  1. Essayez d'éviter l'utilisation de unité de travail. Votre modèle devrait définir les limites transactionnelles.
  2. Essayez d'éviter l'utilisation de des référentiels génériques (notez aussi le point sur IQueryable).
  3. il n'est pas obligatoire de spam votre code avec schéma du dépôt nom.

en outre, Vous pouvez profiter de la lecture sur domaine driven design. Il aide à faire face à la logique complexe des affaires et donne de grandes directives pour rendre le code moins procédurale, plus orientée objet.

2
répondu Arnis Lapsa 2017-05-23 11:52:41

je vais me concentrer sur vos problèmes actuels: pour être honnête, je ne pense pas que vous devriez passer autour de votre ObjectContext. Je pense que cela va conduire à des problèmes. Je suppose qu'un contrôleur ou un service d'affaires passera L'ObjectContext/ITransaction au dépôt. Comment vous assurer que votre ObjectContext est éliminé correctement en aval? Que se passe-t-il lorsque vous utilisez des transactions imbriquées? Qu'est-ce qui gère les retraits, pour les transactions en aval?

je pense que votre le meilleur pari consiste à mettre plus de définition sur la façon dont vous vous attendez à gérer les transactions dans votre architecture. Utiliser TransactionScope dans votre controller / service est un bon début puisque ObjectContext le respecte. Bien sûr, vous pouvez avoir besoin de tenir compte du fait que les contrôleurs/services peuvent faire des appels à d'autres contrôleurs/services qui ont des transactions en eux. Afin de permettre des scénarios où vous voulez le plein contrôle de vos transactions commerciales et les appels de base de données suivantes, vous besoin de créer une sorte de classe TransactionManager qui s'engage, et gère généralement les transactions de haut en bas de votre pile. J'ai trouvé que NCommon fait un travail extraordinaire à la fois à l'abstraction et à la gestion des transactions. Regardez les classes UnitOfWorkScope et TransactionManager. Bien que je ne sois pas d'accord avec L'approche de NCommon de forcer le dépôt à se fier à L'Unité de travail, cela pourrait facilement être refactorisé si vous vouliez.

aussi loin que votre persistantID question va, check this out

1
répondu Jason 2017-05-23 12:23:56