Quel est un moyen pratique de modéliser des tables de recherche dans la conception gérée par le domaine (DDD)?

StackOverflow https://stackoverflow.com/questions/808481

  •  03-07-2019
  •  | 
  •  

Question

J'apprends juste la DDD (le livre d'Eric Evans est ouvert devant moi) et j'ai rencontré un problème pour lequel je ne trouve pas de réponse. Que faites-vous dans DDD lorsque vous essayez simplement d'obtenir une simple liste d'enregistrements de recherche?

Ex.

EmployeeID: 123
EmployeeName: John Doe
État: Alaska (déroulant)
Comté: Wasilla (liste déroulante - sera filtré en fonction de l'état).

Par exemple, supposons que vous ayez un objet Domaine employé, une interface IEmployeeRepository et une classe EmployeeRepository. Ceci sera utilisé par une interface utilisateur pour afficher une liste des employés et des détails individuels. Dans l'interface utilisateur, vous souhaitez utiliser une liste déroulante pour l'État et le comté où réside l'employé. Les comtés disponibles seront filtrés en fonction de l'état choisi.

Malheureusement, les tables de la base de données et l'interface utilisateur sont très différentes. Dans tblEmployees, il contient le code d’État = AK et le code de comté = 02130, et non les noms d’État et de comté.

L'ancienne méthode (avant que je commence cette quête DDD) serait assez simple: il suffit de créer 2 requêtes et d'utiliser un DataReader pour remplir les listes déroulantes. Sous la liste, dans les menus déroulants, se trouve la valeur, qui est automatiquement utilisée dans les publications de formulaire.

Avec DDD, cependant, je ne sais pas comment vous êtes censé faire cela. J'ai d'abord commencé par créer des objets d'État et de comté, ainsi que des référentiels et des interfaces pour les référentiels. Toutefois, l'écriture de 4 classes + 2 interfaces et de la tuyauterie dans les fichiers hbm.xml + Employé Business semble être superflue pour seulement 2 requêtes pour 2 listes déroulantes. Il doit y avoir un meilleur moyen, n'est-ce pas? Je ne changerai pas les archives dans les tables des états ou des comtés de si tôt et même si je le faisais, ce ne serait pas par le biais de cette application. Donc, je ne veux pas vraiment créer d'objets métier pour State and County si je ne suis pas obligé de le faire.

La solution la plus simple que je connaisse consiste à créer une classe d'assistance avec des méthodes qui renvoient des dictionnaires, tels que GetStatesAll (), GetState (), GetCounties () et GetCounty (), mais cela ne va pas du tout dans une perspective DDD.

S'il vous plaît aider. Comment utiliser DDD sans trop d'ingénierie, juste quelques recherches simples?

Solution finale Je pense que j'ai finalement trouvé ma réponse grâce à l'expérience, qui consistait à placer la méthode GetStates () dans sa propre classe d'accès aux données, sans pour autant être une classe de référentiel. Comme je ne faisais que l'accès en lecture seule, je l'ai jeté dans un struct DTO. Comme la base de données était petite, je les ai jeté dans une seule classe, comme Todd décrit ci-dessous.

Mes conclusions:

  1. Les tables de recherche ne sont jamais des objets de valeur, car elles ont TOUJOURS une identité. S'ils n'avaient pas d'identité, vous auriez des doublons, ce qui n'aurait aucun sens.
  2. La table de recherche en lecture seule peut avoir un référentiel, mais n'en a probablement pas besoin. L'objectif d'un référentiel est de réduire la complexité en forçant l'accès uniquement via l'agrégat. En parcourant l'ensemble, vous disposez d'un moyen de vous assurer que les règles commerciales peuvent être appliquées, par exemple, ne pas ajouter de pneus si vous n'avez pas de voiture.
  3. Si vous autorisez la maintenance CRUD sur la table de recherche, il est logique que la table de recherche ait son propre référentiel.
  4. Le fait que j'ai fini par stocker les codes sous forme de structures ne les rend pas des "types de valeur". Fowler dit dans POEAA qu'une structure est un type de valeur. C'est vrai, les structures sont immuables, c'est pourquoi Fowler dit qu'elles sont des "types valeur", mais je les utilisais différemment. J'utilisais des structs comme moyen léger de transmettre des DTO que je n'avais jamais prévu de modifier après leur création initiale. En vérité, les structures que j’utilisais avaient certes des identités, mais comme elles étaient en lecture seule, elles fonctionnaient comme des structures.
  5. Un modèle que je me sers et que je ne vois pas beaucoup ailleurs est de rendre les champs de clé primaires immuables. Ils sont définis par le constructeur, mais ils sont en lecture seule (pas des accesseurs privés) et ne peuvent pas être modifiés une fois l'objet créé.
Était-ce utile?

La solution

Vous voudrez peut-être examiner le concept de Séparation des requêtes de commande . Je ne voudrais pas m'inquiéter des référentiels typés pour les valeurs de recherche, mais j'utiliserais probablement encore des classes de type DTO sur des ensembles de données, etc.

Vous voudrez peut-être passer du temps à lire les blogs de Greg Young à partir de celui-ci au présent. Il ne parle pas de remplissage de données de recherche de manière spécifique, mais il parle souvent de ne pas gérer la fonctionnalité de lecture / création de rapports de votre application via des méthodes typées sur un référentiel.

Autres conseils

À l'aide de DDD, j'ai quelque chose de similaire avec ce qui suit:

interface IAddressService
{
  IList<Country> GetCountries ();
  IList<State> GetStatesByCountry (string country);
  IList<City> GetCitiesByState (string state);
  // snip
}

Pays, État et Ville sont des objets de valeur provenant d'une table de recherche de la base de données.

Eh bien, j'ai lu un article de Mathias Verraes il y a quelque temps qui parlait de ceci ici . Il parle de Séparer les objets de valeur dans le modèle des concepts qui servent l’UI.

Citation de l'article lorsqu'on lui a demandé s'il fallait modéliser des pays en tant qu'entités ou en tant qu'objets de valeur:

  

Rien n’est intrinsèquement faux avec les pays modélisés comme   entités et les stocker dans la base de données. Mais dans la plupart des cas, cela   trop compliquer les choses. Les pays ne changent pas souvent. Lorsqu'un   pays change de nom, c’est en fait, à toutes fins pratiques, une   nouveau pays. Si un pays n’existe plus un jour, vous ne pouvez pas   changez simplement toutes les adresses, car le pays a peut-être été divisé   dans deux pays.

Il a suggéré une approche différente pour introduire un nouveau concept appelé AvailableCountry :

  

Ces pays disponibles peuvent être des entités dans une base de données, des enregistrements dans   JSON, ou même simplement une liste codée en dur dans votre code. (Cela dépend de   si l'entreprise souhaite y accéder facilement via une interface utilisateur.)

<?php

final class Country
{
    private $countryCode;

    public function __construct($countryCode)
    {
        $this->countryCode = $countryCode;
    }

    public function __toString()
    {
        return $this->countryCode;
    }
}

final class AvailableCountry
{
    private $country;
    private $name;

    public function __construct(Country $country, $name)
    {
        $this->country = $country;
        $this->name = $name;
    }

    /** @return Country */
    public function getCountry()
    {
        return $this->country;
    }

    public function getName()
    {
        return $this->name;
    }

}

final class AvailableCountryRepository
{
    /** @return AvailableCountry[] */
    public function findAll()
    {
        return [
            'BE' => new AvailableCountry(new Country('BE'), 'Belgium'),
            'FR' => new AvailableCountry(new Country('FR'), 'France'),
            //...
        ];
    }

    /** @return AvailableCountry */
    public function findByCountry(Country $country)
    {
        return $this->findAll()[(string) $country];
    }
}

Il semble donc qu’il existe une troisième solution qui consiste à modéliser les tables de recherche en tant qu’objets et entités de valeur.

Assurez-vous de vérifier la section des commentaires pour des discussions sérieuses sur cet article.

L'état et le comté ne sont pas des entités, mais des objets de valeur. Ils ne sont pas le sujet de votre système. La façon dont vous avez dit que vous avez traité ces derniers est OK. Quand modifierez-vous les enregistrements d'état ou de comté dans votre base de données, en fonction des modifications apportées à l'état de votre modèle de domaine? Non, ils n'auront donc pas besoin d'un référentiel.

Vous ne lisez pas le bon livre si vous voulez apprendre à utiliser le DDD sans trop le compliquer. : -)

La solution la plus simple que vous proposez convient si elle répond à vos besoins. L'encapsulation des données d'adresse dans des objets métier peut être aussi simple ou aussi compliquée que le demande votre application. Par exemple, l'objet State entretient une relation un-à-plusieurs avec County. Ainsi, Employee doit simplement référencer un comté si vous choisissez de le modéliser de cette manière. Je ne ferais que présenter ce type de complexité si nécessaire.

De plus, je ne pense pas qu'il y ait beaucoup à gagner à la définition d'interfaces pour vos référentiels, sauf s'il est réellement possible que vous disposiez de plusieurs référentiels pour vos objets.

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