2010-09-02 3 views
8

Il est possible (même probable) que je ne croque pas complètement le concept d'une «unité de travail». Fondamentalement, je le vois comme une sorte de transaction large utilisée dans un environnement orienté objet. Démarrer l'unité de travail, interagir avec les objets, valider ou annuler. Mais comment cela se décompose-t-il en transactions réelles dans les magasins de données derrière ces objets?Unité de travail avec plusieurs sources de données?

Dans un système avec un seul DB et un ORM (tel que NHibernate), c'est facile. La transaction peut être maintenue via l'ORM. Mais qu'en est-il d'un système où les modèles de domaines personnalisés masquent de nombreuses sources de données disparates? Et toutes ces sources de données ne sont-elles pas des bases de données relationnelles? (Actuellement, beaucoup de choses sont faites sur le système de fichiers.)

Actuellement, je suis bloqué sur l'idée que «vous ne pouvez simplement pas gérer une transaction sur une base de données SQL2005, une base de données SQL2000, une base de données DB2 et le système de fichiers tout dans la même opération commerciale «atomique». " Donc pour l'instant c'est la responsabilité des développeurs de l'équipe (qui travaillent généralement indépendamment les uns des autres) de maintenir les transactions manuellement dans le code. Chaque base de données peut avoir des transactions correctes, mais l'ensemble de l'activité commerciale est vérifiée manuellement et équilibrée à chaque étape significative du processus. Toutefois, avec la complexité croissante du domaine et le renouvellement standard des développeurs, cette approche deviendra de plus en plus difficile et susceptible d'entraîner des erreurs au fil du temps.

Quelqu'un a-t-il des conseils ou des exemples sur la meilleure façon d'aborder un domaine comme celui-ci, ou comment il a été traité auparavant? Dans ce cas, le «domaine» actuel en est encore à ses balbutiements, évoluant comme un prototype pour se développer un jour et consommer/remplacer un vaste écosystème d'applications héritées disparates. Il y a donc beaucoup de place pour re-concevoir et ré-factoriser. Pour référence, une vue de 10 000 pieds de la conception que je vise actuellement est: Une grande collection de petites applications client aussi stupides que possible appelant un service central basé sur les messages. Le service est l'entrée dans le «noyau de domaine» et peut être considéré comme une grande application de style MVC. Les demandes sont faites au service (un peu comme les «actions») qui sont récupérées par les gestionnaires (un peu comme les «contrôleurs»). Tout ce qui est procédural va là-bas. Ils interagissent avec les modèles, qui contiennent toutes les règles métier. Les modèles publient des événements dont les auditeurs ("services" - cette partie est encore trouble dans la conception et sujets à amélioration) relèvent et manipulent en interagissant avec les référentiels (base de données x, base de données y, système de fichiers, email, toute ressource externe). Toutes les dépendances joyeusement injectées en conséquence.

Désolé pour toute la verbosité :) Mais si quelqu'un a un conseil, j'aimerais l'entendre. Même (surtout) si ce conseil est "votre design est mauvais, essayez ceci à la place ..." Merci!

+1

Avez-vous déjà consulté le coordinateur de transactions distribuées? http://msdn.microsoft.com/en-us/library/ms684146(VS.85).aspx –

+0

@Michael - J'ai eu de la chance en utilisant TransactionScope/MSDTC avec des solutions SqlServer uniquement. La répartition à travers le système de fichiers et les autres SGBDR peut être plus délicate. OP parle de coordonner le travail sur divers moteurs de base de données, c'est pourquoi je ne suggère pas MSDTC comme une réponse. –

Répondre

9

J'ai déjà travaillé sur un système qui pourrait accomplir cela, et c'est assez simple. Puisque votre projet est à ses débuts, peut-être que cela pourrait être une information utile pour vous. Malheureusement, je n'ai plus accès au code, mais je suis toujours à l'aise pour décrire comment cela fonctionne.

Ce que j'avais fait a été construit mes dépôts en utilisant une mise en œuvre de modèle de référentiel générique. Le type de référentiel de base serait toujours des références par les services et UoW. Par souci de discussion, nous l'appellerons BaseRepository. "T" serait restreint aux implémentations IEntity, qui désignaient un objet de domaine. À partir de BaseRepository, j'avais créé un autre ensemble de classes de base pour le compositing, comme SqlBaseRepository, XmlBaseRepository, etc.

L'UoW se soucie seulement que quelque chose soit du type BaseRepository, où la fonctionnalité principale existerait. CUD de base (de CRUD) serait représenté, fournissant les équivalents pour les créations, les mises à jour et les suppressions.Ce que chacun d'entre eux ferait serait de créer un délégué et de le placer dans une file d'attente dans le UoW, en transmettant également des informations sur le type de transaction qu'il allait être, et les données appropriées requises pour le compléter. L'UoW commencerait à maintenir une liste des référentiels qui allaient avoir besoin d'être impliqués dans la transaction, mais ne se souciait toujours pas de savoir de quel type il s'agissait. Efficacement, faire la queue ici, c'est comme s'enrôler dans une transaction. Le BaseRepository a défini une méthode abstraite appelée quelque chose comme .ApplyChange(). Une fois que .Commit() a été appelé sur le UoW, il créerait un TransactionScope() et commencerait à appeler les delagates dans la liste, en renvoyant l'information à .ApplyChange(). L'implémentation réelle de .ApplyChange() existe dans la base de référentiel spécifique, c'est-à-dire la SqlRepositoryBase, etc. et pourrait également être surchargée par l'implémentation.

Où il est devenu difficile, pour moi au moins, revenait en arrière. Je ne traitais qu'une seule base de données, mais j'avais parfois des modifications basées sur des fichiers. J'ai ajouté une méthode .RevertChange() et j'ai commencé à suivre l'état d'origine et les états modifiés afin que je puisse fondamentalement appliquer un reverse-delta pour revenir à l'endroit où j'étais sur la pile de fichiers.

Je souhaite que je pourrais être plus précis sur la mise en œuvre, mais cela fait plus d'un an que j'ai vu le code maintenant. Je peux vous dire que la base du code original provient du livre .NET Domain-Driven Design with C#: Problem - Design - Solution de Tim McCarthy. Une grande partie de l'implémentation de mon référentiel reposait sur ses exemples, une grande partie de ma personnalisation intervenant sur les UoW et leur implémentation.

J'espère que cela aide, un peu! :-)

+0

C'est très utile, en fait. Pour être honnête, je pense que la recommandation du livre sera la partie la plus utile à long terme. Peut-être qu'il est temps que je ralentisse le bricolage et que je rattrape mon retard de lecture. Je suis probablement au point de ma carrière où ce livre et les livres sur lesquels l'auteur s'est basé (en particulier le livre de Fowler, que je remets depuis quelque temps) vont être une bonne base pour aller de l'avant. Merci! – David

+1

Pas de problème, David. Ce livre a aussi un projet sur CodePlex, que j'ai oublié de mentionner. Vous pouvez au moins tirer sur la source et lancer les pneus. ;-) http://dddpds.codeplex.com/ –

Questions connexes