Qual è un modo pratico per modellare le tabelle di ricerca in Domain Driven Design (DDD)?

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

  •  03-07-2019
  •  | 
  •  

Domanda

Sto solo imparando DDD (il libro di Eric Evans è aperto davanti a me) e ho riscontrato un problema per il quale non riesco a trovare una risposta. Cosa fai in DDD quando stai solo cercando di ottenere un semplice elenco di record di ricerca?

Ex.

EmployeeID: 123
Nome Dipendente: John Doe
Stato: Alaska (a discesa)
Contea: Wasilla (elenco a discesa: verrà filtrato in base allo stato).

Ad esempio, supponiamo che tu abbia un oggetto dominio Employee, un'interfaccia IEmployeeRepository e una classe EmployeeRepository. Questo verrà utilizzato da un'interfaccia utente per mostrare un elenco di dipendenti e dettagli individuali. Nell'interfaccia utente, si desidera utilizzare un menu a discesa per lo stato e la contea in cui risiede il dipendente. Le contee disponibili verranno filtrate in base allo stato scelto.

Sfortunatamente, le tabelle del database e l'interfaccia utente sembrano molto diverse. In tblEmployees, contiene il codice di stato = AK e il codice di contea = 02130, non i nomi di stato e di contea.

Il vecchio modo (prima di iniziare questa ricerca DDD) sarebbe piuttosto semplice, basta creare 2 query e utilizzare un DataReader per popolare i menu a discesa. Sotto la visualizzazione nei menu a discesa è presente il valore, che viene automaticamente utilizzato nei post dei moduli.

Con DDD, tuttavia, non sono sicuro di come dovresti farlo. Ho iniziato creando oggetti State e County, nonché repository e interfacce per i repository. Tuttavia, scrivere 4 classi + 2 interfacce e l'impianto idraulico nei file hbm.xml + oggetti Employee Business sembra eccessivo per solo 2 query per 2 menu a discesa. Deve esserci un modo migliore, vero? Non cambierò presto i record nelle tabelle dello stato o della contea e anche se lo facessi, non sarebbe attraverso questa applicazione. Quindi non voglio davvero creare oggetti business per lo stato e la contea se non devo.

La soluzione più semplice che vedo è semplicemente creare una classe helper con metodi che restituiscono dizionari, come GetStatesAll (), GetState () e GetCounties () e GetCounties (), ma sembra sbagliato dal punto di vista DDD.

Per favore aiuto. Come posso usare DDD senza sovrastimare solo un paio di semplici ricerche?

Soluzione finale Penso di aver finalmente trovato la mia risposta attraverso l'esperienza, che consisteva nel mettere il metodo GetStates () nella propria classe di accesso ai dati, sebbene non in una classe di repository. Dato che stavo solo facendo l'accesso in sola lettura, l'ho gettato in una struttura DTO. Dato che il database era piccolo, li ho buttati del tutto in una singola classe, come descritto di seguito da Todd.

Le mie conclusioni:

  1. Le tabelle di ricerca non sono MAI oggetti valore, poiché le tabelle di ricerca hanno SEMPRE un'identità. Se non avessero un'identità, avresti duplicati, il che non avrebbe molto senso.
  2. La tabella di ricerca di sola lettura può avere un repository, ma probabilmente non ne ha bisogno. L'obiettivo di un repository è ridurre la complessità forzando l'accesso solo attraverso l'aggregato. L'esame dell'aggregato ti fornisce un modo per garantire che le regole aziendali possano essere applicate, come non aggiungere pneumatici se non hai una macchina.
  3. Se si consente la manutenzione CRUD sulla tabella di ricerca, è logico che la tabella di ricerca abbia un proprio repository.
  4. Il fatto che ho finito per memorizzare i codici come strutture non li rende "tipi di valore". Fowler afferma in POEAA che una struttura è un tipo di valore. È vero, le strutture sono immutabili, motivo per cui Fowler afferma che sono "tipi di valore", tuttavia le stavo usando in modo diverso. Stavo usando le strutture come un modo leggero per aggirare i DTO che non avevo mai pensato di cambiare dopo la loro creazione iniziale. In verità, le strutture che ho usato avevano effettivamente delle identità, ma poiché erano di sola lettura hanno funzionato come strutture.
  5. Uno schema che ho usato e che non vedo molto altrove è rendere immutabili i campi chiave primari. Sono impostati dal costruttore, ma sono di sola lettura (non accessi privati) e non possono essere modificati una volta creato l'oggetto.
È stato utile?

Soluzione

Potresti voler esaminare il concetto di Separazione query comando . Non mi preoccuperei dei repository digitati per i valori di ricerca, ma probabilmente utilizzerei comunque le classi di tipo DTO sui set di dati, ecc ...

Potresti passare un po 'di tempo a leggere i blog di Greg Young a partire da questo al presente. Non parla in particolare di compilare i dati di ricerca, ma spesso parla di non gestire la funzionalità di lettura / reporting della tua applicazione attraverso metodi digitati su un repository.

Altri suggerimenti

Usando DDD ho qualcosa di simile con il seguente:

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

Paese, stato e città sono oggetti valore che provengono da una tabella di ricerca nel database.

Beh, ho letto un articolo di Mathias Verraes qualche tempo fa parlando di questo qui . Parla della separazione degli oggetti valore nel modello dai concetti che servono l'interfaccia utente.

Citando l'articolo quando viene chiesto se modellare Paesi come entità o oggetti valore:

  

Non c'è nulla di intrinsecamente sbagliato nei paesi dei modelli come   entità e memorizzandole nel database. Ma nella maggior parte dei casi, quello   cose complicate. I paesi non cambiano spesso. Quando un   il nome del Paese cambia, infatti, a tutti gli effetti pratici, a   nuovo paese. Se un giorno un paese non esiste più, puoi & # 8217; t   cambia semplicemente tutti gli indirizzi, perché probabilmente il paese è stato diviso   in due paesi.

Ha suggerito un approccio diverso per introdurre un nuovo concetto chiamato AvailableCountry :

  

Questi paesi disponibili possono essere entità in un database, record in a   JSON, o anche semplicemente un elenco hardcoded nel tuo codice. (Dipende da   se l'azienda desidera accedervi facilmente tramite un'interfaccia utente.)

<?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];
    }
}

Quindi sembra che esista una terza soluzione che consiste nel modellare le tabelle di ricerca sia come oggetti valore che come entità.

A proposito, assicurati di controllare la sezione dei commenti per alcune discussioni serie sull'articolo.

Lo stato e la contea non sono entità, ma oggetti valore. Non sono l'oggetto del tuo sistema. Il modo in cui hai detto di averli trattati in precedenza è OK. Quando cambierai i record di stato o di contea nel tuo database, in base alle modifiche nello stato del tuo modello di dominio? No, quindi questi non avranno bisogno di un repository.

Stai leggendo il libro sbagliato se vuoi imparare a fare DDD senza complicarlo troppo. : -)

La soluzione più semplice che stai proponendo va bene se soddisfa le tue esigenze. Incapsulare i dati degli indirizzi negli oggetti business può essere semplice o complicato come richiede la tua applicazione. Ad esempio, l'oggetto Stato ha una relazione uno-a-molti con la Contea, quindi il Dipendente deve davvero fare riferimento a una Contea se si sceglie di modellarla in quel modo. Vorrei introdurre questo tipo di complessità solo se necessario.

Inoltre, non penso che ci sia molto da guadagnare definendo le interfacce per i tuoi repository a meno che non ci sia una reale possibilità che tu possa avere più repository per i tuoi oggetti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top