¿Cuál es una forma práctica de modelar las tablas de búsqueda en el Diseño impulsado por Dominio (DDD)?


Estoy aprendiendo DDD (el libro de Eric Evans está abierto frente a mí) y me he encontrado con un problema para el que no puedo encontrar una respuesta. ¿Qué haces en DDD cuando solo intentas obtener una lista simple de registros de búsqueda?

Ex.

Empleado: 123
Nombre del empleado: John Doe
Estado: Alaska (desplegable)
Condado: Wasilla (desplegable be se filtrará según el estado).

Por ejemplo, supongamos que tiene un objeto de dominio Empleado, unployployeerepository interfaz y una clase EmployeeRepository. Esto será utilizado por una interfaz de usuario para mostrar una lista de empleados y detalles individuales. En la interfaz de usuario, desea usar un menú desplegable para el estado y el condado donde vive el empleado. Los condados disponibles se filtrarán según el estado elegido.

Desafortunadamente, las tablas de la base de datos y la interfaz de usuario se ven muy diferentes. En tblEmployees, contiene Código de Estado = AK y Código de Condado = 02130, no los Nombres de Estado y Condado.

La vieja manera (antes de I comenzó esta misión DDD) sería bastante sencillo, solo tiene que crear 2 consultas y utilizar un DataReader para rellenar los menús desplegables. Debajo de la pantalla en los desplegables está el valor, que se usa automáticamente en las publicaciones de formularios.

Con DDD, sin embargo, no estoy seguro de cómo se supone que hacer esto. Primero comencé creando objetos de Estado y Condado, así como repositorios e interfaces para los repositorios. Sin embargo, la escritura de 4 clases + 2 interfaces y la fontanería en el hbm.archivos xml + Employee Business objects parece exagerado para solo 2 consultas para 2 desplegables. Tiene que haber una mejor manera, ¿no? No voy a cambiar los registros en las tablas del Estado o Condado en el corto plazo e incluso si lo hiciera, no sería a través de esta aplicación. Así que realmente no quiero crear objetos de negocio para el Estado y el Condado si no tengo que hacerlo.

La solución más simple que veo es simplemente crear una clase helper con métodos que devuelvan diccionarios, como GetStatesAll(), getState () y GetCounties () y GetCounty (), pero eso se siente mal desde una perspectiva DDD.

Por Favor ayuda. ¿Cómo puedo usar DDD sin sobreingeniería solo un par de simples búsquedas?

Solución final Creo que finalmente encontré mi respuesta a través de la experiencia, que fue poner el método GetStates() en su propia clase Data Access, aunque no una clase repository. Como solo estaba haciendo acceso de solo lectura, lo lancé a un DTO de estructura. Dado que la base de datos era pequeña, los arrojó en una sola clase, como Todd describió a continuación.

Mis conclusiones:

  1. Las tablas de búsqueda NUNCA son objetos de valor, porque las tablas de búsqueda SIEMPRE tienen una identidad. Si no tuvieran una identidad, tendrías duplicados, lo que no tendría mucho sentido.
  2. La tabla de búsqueda de solo lectura puede tener un repositorio, pero probablemente no lo necesite. El objetivo de un repositorio es reducir la complejidad forzando el acceso solo a través del agregado. Pasando por el aggregate le proporciona una manera de asegurarse de que las reglas comerciales se puedan hacer cumplir, como no agregar neumáticos si no tiene un automóvil.
  3. Si permite el mantenimiento de CRUD en la tabla de búsqueda, entonces tiene sentido que la tabla de búsqueda tenga su propio repositorio.
  4. El hecho de que termine almacenando los códigos como estructuras no los convierte en "tipos de valor". Fowler dice en POEAA que una estructura es un tipo de valor. Eso es cierto, las estructuras son inmutables, por lo que Fowler dice que son "tipos de valor", sin embargo, los estaba usando de manera diferente. Estaba usando estructuras como una forma liviana de pasar DTO que nunca planeé cambiar después de su creación inicial. En verdad, las estructuras que utilicé tenían, de hecho, identidades, pero como eran de solo lectura funcionaban como estructuras.
  5. Un patrón que he estado usando que no veo mucho en otros lugares es hacer que los campos de clave primaria sean inmutables. Son configurados por el constructor, pero son de solo lectura (no de acceso privado) y no se puede cambiar una vez que se crea el objeto.
Author: John, 2009-04-30

5 answers

Es posible que desee examinar el concepto de Separación de Consultas de comandos. No me preocuparía por los repositorios escritos para los valores de búsqueda,pero probablemente todavía usaría clases de tipo DTO sobre conjuntos de datos, etc...

Es posible que desee pasar algún tiempo leyendo los blogs de Greg Young a partir de este hasta el presente. No habla de rellenar datos de búsqueda específicamente, pero a menudo habla de no manejar la funcionalidad de lectura / informes de su aplicación a través de métodos en un repositorio.

 5
Author: Daniel Auger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 21:40:03

Usando DDD tengo algo similar con lo siguiente:

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

Country, State y City son objetos de valor que provienen de una tabla de búsqueda en la base de datos.

 6
Author: Todd Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 21:12:41

El estado y el condado no son entidades, sino objetos de valor. No son el tema de su sistema. La forma en que dijiste que los trataste anteriormente está bien. ¿Cuándo cambiará los registros del estado o condado en su base de datos, en función de los cambios en el estado de su modelo de dominio? No, por lo que estos no necesitarán un repositorio.

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 20:14:42

Estás leyendo el libro equivocado si quieres aprender a hacer DDD sin complicarlo demasiado. :-)

La solución más simple que está proponiendo está bien si satisface sus necesidades. Encapsular datos de direcciones en objetos de negocio puede ser tan simple o complicado como lo requiera su aplicación. Por ejemplo, el objeto State tiene una relación de uno a muchos con el Condado, por lo que el empleado realmente solo necesita hacer referencia a un condado si elige modelarlo de esa manera. Yo sólo presentaría ese tipo de complejidad si es necesario.

Además, no creo que haya mucho que ganar definiendo interfaces para sus repositorios a menos que haya una posibilidad real de que pueda tener múltiples repositorios para sus objetos.

 2
Author: Jamie Ide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-30 20:16:18

Bueno, leí un artículo de Mathias Verraeshace algún tiempo hablando de esto aquí. Habla de Separar los objetos de valor en el modelo de los conceptos que sirven a la interfaz de usuario.

Citando el artículo cuando se le pregunta si modelar Países como entidades u valorar objeto:

No hay nada intrínsecamente malo con los países de modelado como entidades y almacenarlas en la base de datos. Pero en la mayoría de los casos, que complicando las cosas. Los países no cambia a menudo. Cuando un el nombre del país cambia, es de hecho, para todos los efectos prácticos, un nuevo país. Si un país un día ya no existe, no se puede simplemente cambie todas las direcciones, porque posiblemente el país se dividió en dos países.

Sugirió un enfoque diferente para introducir un nuevo concepto llamado AvailableCountry:

Estos países disponibles pueden ser entidades en una base de datos, registros en un JSON, o incluso simplemente una lista codificada en su código. (Que depende de si la empresa quiere un acceso fácil a ellos a través de una interfaz de usuario.)

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

Así que parece que hay una 3ra solución que es modelar las tablas como objetos de valor y entidades.

Por cierto, asegúrese de revisar la sección de comentarios para algunas discusiones serias sobre el artículo.

 2
Author: Songo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-26 12:47:16