Question

Après avoir lu les livres d'Evan et de Nilsson, je ne sais toujours pas comment gérer l'accès aux données dans un projet dirigé par un domaine. Si les méthodes CRUD font partie des référentiels, par exemple, OrderRepository.GetOrdersByCustomer (client) ou si elles font partie des entités suivantes: Customer.GetOrders (). Cette dernière approche semble plus orientée objet, mais elle distribuera l'accès aux données pour un type d'entité unique entre plusieurs objets, à savoir Customer.GetOrders (), Invoice.GetOrders (), ShipmentBatch.GetOrders (), etc. Qu'en est-il de l'insertion et de la mise à jour?

Était-ce utile?

La solution

Les méthodes CRUD-ish doivent faire partie du référentiel ... ish. Mais je pense que vous devriez demander pourquoi vous avez un tas de méthodes CRUD. Que font-ils vraiment ? A quoi servent-ils vraiment ? Si vous appelez les modèles d'accès aux données utilisés par votre application, je pense que cela rend le référentiel beaucoup plus utile et vous évite d'avoir à effectuer une opération à la volée lorsque certains types de modifications se produisent dans votre domaine.

CustomerRepo.GetThoseWhoHaventPaidTheirBill()

// or

GetCustomer(new HaventPaidBillSpecification())

// is better than

foreach (var customer in GetCustomer()) {
    /* logic leaking all over the floor */
}

"Enregistrer" Les méthodes de type doivent également faire partie du référentiel.

Si vous avez des racines agrégées, vous évitez ainsi une explosion du référentiel ou une logique dispersée: vous n'avez pas 4 x nombre de modèles d'accès aux données d'entités, mais uniquement ceux que vous utilisez réellement sur les racines agrégées. .

C'est mon 0,02 $.

Autres conseils

DDD préfère généralement le modèle de référentiel au modèle d'enregistrement actif que vous indiquez avec Customer.Save.

Un des inconvénients du modèle Active Record est qu’il présume un modèle de persistance unique, à l’exception de certains codes particulièrement intrusifs (dans la plupart des langues).

L'interface du référentiel est définie dans la couche de domaine, mais ne sait pas si vos données sont stockées dans une base de données ou non. Avec le modèle de référentiel, je peux créer un InMemoryRepository afin de tester la logique de domaine de manière isolée et utiliser l'injection de dépendances dans l'application pour que la couche service instancie un SqlRepository, par exemple.

Pour beaucoup de gens, disposer d'un référentiel spécial uniquement pour tester les sons sonores, mais si vous utilisez le modèle de référentiel, vous constaterez peut-être que vous n'avez pas vraiment besoin d'une base de données pour votre application particulière; Parfois, un simple FileRepository fera l'affaire. Se marier à une base de données avant de savoir que vous en avez besoin est potentiellement limitant. Même si une base de données est nécessaire, l'exécution de tests sur un InMemoryRepository est beaucoup plus rapide.

Si vous n'avez pas beaucoup de logique de domaine, vous n'avez probablement pas besoin de DDD. ActiveRecord est tout à fait adapté à de nombreux problèmes, notamment si vous avez principalement des données et juste un peu de logique.

Revenons un instant en arrière. Evans recommande que les référentiels renvoient des racines agrégées et pas seulement des entités. Donc, en supposant que votre client soit une racine agrégée comprenant des commandes, lorsque vous extrayez le client de son référentiel, les commandes l'accompagnent. Pour accéder aux commandes, naviguez la relation entre le client et les commandes.

customer.Orders;

Pour répondre à votre question, les opérations CRUD sont présentes sur les référentiels racine agrégés.

CustomerRepository.Add(customer);
CustomerRepository.Get(customerID);
CustomerRepository.Save(customer);
CustomerRepository.Delete(customer);

Je l'ai fait dans les deux sens dont vous parlez. Mon approche préférée maintenant est la méthode persistante ignorante (ou PONO - Objet .Net simple) où vos classes de domaine s'inquiètent uniquement d'être des classes de domaine. Ils ne savent rien de leur persistance ou même de leur persistance. Bien sûr, vous devez parfois être pragmatique à ce sujet et permettre des choses comme un identifiant (mais même dans ce cas, j'utilise simplement un super type de couche qui a l'identifiant, de sorte que je puisse avoir un point unique où des valeurs telles que la valeur par défaut sont actives)

La raison principale en est que je m'efforce de suivre le principe de la responsabilité unique. En suivant ce principe, j'ai trouvé mon code beaucoup plus testable et maintenable. Il est également beaucoup plus facile d’apporter des modifications lorsque cela est nécessaire, car je n’ai qu’une chose à laquelle réfléchir.

Une chose à surveiller est la méthode à laquelle les référentiels peuvent souffrir. GetOrderbyCustomer .. GetAllOrders ... GetOrders30DaysOld .. etc etc. Une bonne solution à ce problème consiste à examiner le modèle d'objet de requête. Et puis vos référentiels peuvent simplement prendre un objet de requête à exécuter.

Je vous recommanderais également fortement de rechercher quelque chose comme NHibernate. Il comprend de nombreux concepts qui rendent les référentiels si utiles (cartes d’identité, antémémoire, objets de requête, etc.)

Même dans un DDD, je voudrais que les classes et les routines d'accès aux données soient séparées des entités.

Les raisons sont,

  1. Amélioration de la testabilité
  2. Séparation des préoccupations et conception modulaire
  3. Plus facile à gérer à long terme, à mesure que vous ajoutez des entités, des routines

Je ne suis pas un expert, juste mon opinion.

Le problème avec l'application de DDD & P de Nilsson est qu'il commence toujours par "je ne ferais pas cela dans une application du monde réel, mais ...". et ensuite son exemple suit. Retour au sujet: Je pense que OrderRepository.GetOrdersByCustomer (client) est la voie à suivre, mais il y a aussi une discussion sur la liste de diffusion ALT.Net ( http://tech.groups.yahoo.com/group/altdotnet/ ) à propos de DDD.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top