2009-10-04 8 views
16

Ho implementato il lato comandi di DDD utilizzando il modello di dominio e gli archivi, ma come posso implementare il lato query?Come implementare il lato query di CQRS in DDD?

Devo creare un modello di dominio completamente nuovo per l'interfaccia utente, e dove è conservato nella struttura del progetto ... nel livello dominio, nel livello dell'interfaccia utente, ecc.?

Inoltre, cosa utilizzo come meccanismo di query, posso creare nuovi repository specificatamente per gli oggetti del dominio dell'interfaccia utente, qualcosa di diverso dai repository o qualcos'altro?

+3

Ho appena trovato un post sul blog di Jak Charlton che descrive il motivo per cui ha deciso di non utilizzare DDD per l'interrogazione: "Il lato Query di CQS non richiede entità fortemente tipizzate, né richiede DTI fortemente tipizzati - dato che sono in gran parte dati ad-hoc che mantengono queste entità e DTO consumerebbero una quantità sproporzionata di tempo di sviluppo per qualcosa che un DataTable può gestire più che adeguatamente " http://devlicio.us/blogs/casey/archive/2009/ 06/22/we-are-not-doing-ddd-part-two-cqs.aspx – rohancragg

risposta

6

Dalla mia comprensione di CQRS è possibile creare un set di DTO che soddisfano i requisiti degli schermi dell'interfaccia utente o delle applicazioni che potrebbero aver bisogno di consumarli.

Laddove questo esista nel progetto è basato sui requisiti poiché dipenderebbe se si desidera esporre questi DTO tramite servizi Web. In questo caso non lo inserirò nel livello Web ma piuttosto nel livello Applicazione o in un livello Façade dedicato.

Quindi si dispone di un repository di sola lettura o di un livello di accesso ai dati che popola direttamente i DTO. Penso che il lato Query delle cose dovrebbe essere ottimizzato per le prestazioni di lettura, nel qual caso le query dirette/stored procedure sulle viste del database o sulle tabelle e SqlDataReaders farebbero il lavoro migliore qui. Ma sarebbe sicuramente la pena di astrarre questo accesso dietro un'interfaccia in modo da poter aggiungere un'implementazione memorizzata nella cache più avanti lungo la traccia.

Se si sta utilizzando un ORM e si desidera eseguire il mapping dalle entità dominio alle DTO, è possibile che si disponga di un QueryRepository generico che ha metodi che prendono un ISpecification o un costrutto simile per la definizione delle query e un oggetto DtoAssembler per la creazione Dtos dai tuoi oggetti Dominio. Quindi avere un'implementazione ha un oggetto di prima classe per ciascuna query che si intende eseguire.

Ecco un esempio abbastanza elaborato ma spero che ti dia un'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; 
     } 
    } 
+0

Ho trovato interessante, puoi chiarire una cosa? il repository di query e l'interfaccia di specifica, entrambi sono chiaramente accoppiati con la tecnologia ORM no? In questo caso, credo che il framework delle entità. Non dovrebbe essere permesso di essere astratto? –

3

Penso willbt ti ha dato un ottimo starting point.

Vorrei aggiungere che se si sceglie di continuare a utilizzare l'ORM come strategia di accesso ai dati per le query, si consiglia di prendere in considerazione la definizione di una strategia di recupero personalizzata in base ai dati che ci si aspetta di dover accedere (Sto pensando specificamente a NHibernate qui, comunque). Ciò significa che puoi decidere se caricare o caricare in modo pigro gli oggetti e le raccolte associati a un particolare oggetto Aggregate Root.

Il NCommon project di Ritesh Rao offre una dimostrazione eccellente (work in progress) di come definire una diversa strategia di recupero per scopi diversi.

Ritesh explains it really bene nel suo blog.

Andare avanti e dare un'occhiata alla fonte:

Negli Repository_For_Uses_Registered_Fetching_Strategies 'prova la chiamata alla

NHRepository<Order>().For<NHRepositoryTests>() 

... fa sì che il fe Strategie tching registrate contro la classe NHRepositoryTests da utilizzare, e quindi OrderItems e Products saranno caricati senza problemi con le configurazioni di mapping di NHibernate.

+1

Questo è un punto valido. Tuttavia si applica solo se dovessi restituire le tue Entità al tuo livello di facciata e quindi mappare a DTO. Il mio suggerimento sarebbe quello di utilizzare IQueryable restituito e proiettare direttamente nel DTO. In questo modo si evita qualsiasi FetchStrategies. Si può anche fare la proiezione anche a livello di mappatura NHibernate. – willbt

+0

Certo! Sì grazie. Sto ancora facendo i conti con come avere NHibernate.Linq cambia il gioco, ma se guardi come Ritesh sta abbracciando IQueryable vedrai che Certinaly 'prende' e sta costruendo cose buone intorno ad esso (cioè Specifiche che prendono un Espressione nel loro costruttore). I collegamenti – rohancragg

+0

ora sono aggiornati alle posizioni GitHub – rohancragg

Problemi correlati