domain driven design - net - ¿Cómo implementar el lado de consulta de CQRS en DDD?
microservices domain driven design (2)
He implementado el lado de comando de DDD usando el modelo de dominio y los repositorios, pero ¿cómo implemento el lado de consulta?
¿Creo un modelo de dominio completamente nuevo para la interfaz de usuario, y dónde se guarda esto en la estructura del proyecto ... en la capa de dominio, la capa de interfaz de usuario, etc.?
Además, ¿qué uso como mi mecanismo de consulta, creo nuevos repositorios específicamente para los objetos de dominio de UI, algo distinto a los repositorios, o algo más?
Creo que willbt te ha dado un buen punto de partida .
Me gustaría agregar que si opta por seguir utilizando el ORM como la estrategia de acceso a los datos para las consultas, le recomendamos que considere la posibilidad de definir una estrategia de búsqueda adaptada a los datos a los que espera acceder. Pensando específicamente en NHibernate aquí, por cierto). Lo que esto significa es que puede decidir si cargar de forma perezosa o cargar con ansias los objetos y las colecciones asociadas con un objeto particular de raíz agregada .
El proyecto NCommon de Ritesh Rao ofrece una excelente demostración (trabajo en progreso) de cómo definir una estrategia de búsqueda diferente para diferentes propósitos.
Ritesh lo explica muy bien en su blog.
Sigue adelante y echa un vistazo a la fuente:
- Aquí está la interfaz IFetchingStrategy
- y esto muestra el uso de estrategias de búsqueda en una prueba unitaria.
En la prueba ''Repository_For_Uses_Registered_Fetching_Strategies'' la llamada a
NHRepository<Order>().For<NHRepositoryTests>()
... hace que se utilicen las estrategias de recuperación registradas contra la clase NHRepositoryTests, y por lo tanto, los artículos de pedido y los productos se cargarán con impaciencia y sin problemas con las configuraciones de mapeo de NHibernate.
Desde mi entendimiento de CQRS, crearía un conjunto DTO que cumpla con los requisitos de las pantallas de interfaz de usuario o las aplicaciones que pueden necesitar consumirlas.
El hecho de que exista esto en el proyecto se basa en los requisitos, ya que dependería si usted expusiera estos DTO a través de servicios web. En cuyo caso no lo pondría en la Capa Web, sino en la capa de Aplicación o en una capa de Fachada dedicada.
Entonces tendría un repositorio de solo lectura o una capa de acceso a datos que rellena los DTO directamente. Creo que la parte de las consultas debe optimizarse para el rendimiento de lectura, en cuyo caso las consultas directas / procedimientos almacenados en vistas o tablas de bases de datos y SqlDataReaders harían el mejor trabajo aquí. Pero definitivamente valdría la pena abstraer este acceso detrás de una interfaz para que pueda agregar una implementación en caché más adelante.
Si está usando un ORM y desea mapear desde sus entidades de dominio a los DTO, entonces podría tener un QueryRepository genérico que tiene métodos que toman una especificación de IS o construcción similar para definir sus consultas, luego un objeto DtoAssembler para crear los Dtos desde su dominio objetos. Luego, tener una implementación tiene un objeto de primera clase para cada una de las consultas que va a realizar.
Aquí hay un ejemplo bastante artificial, pero espero que te dé una idea.
public interface ISpecification<T>
{
Expression<Func<T, bool>> Predicate { get; }
}
public class ActiveCustomersSpecification : ISpecification<Customer>
{
private Expression<Func<Customer, bool>> predicate;
public ActiveCustomersSpecification()
{
predicate = c => c.IsActive;
}
#region ISpecicfication<Customer> Members
public Expression<Func<Customer, bool>> Predicate
{
get { return predicate; }
}
#endregion
}
public interface IQueryRepository<T>
{
IQueryable<T> GetQuery(ISpecification<T> specification);
IEnumerable<T> FindAllBy(ISpecification<T> specification);
}
public class CustomerDtoAssembler
{
public CustomerDto AssembleFrom(Customer customer)
{
var customerDto = new CustomerDto
{
Id = customer.Id
};
return customerDto;
}
}