Comando / query al posto del repository

1

Sto pensando all'implementazione del comando / modello di query e ho la seguente soluzione:

Interfaccia per le query:

public interface IQuery<TResult, TArg> 
    where TResult: class 
    where TArg: class
{
    TResult Execute(TArg query);
}

Implementazione:

 public class TreesTransQuery : IQuery<List<Trans>, GetTree>
    {
        private readonly DatabaseContext _context;
        public TreesTransQuery(DatabaseContext context)
        {
            _context = context;
        }

        public List<Trans> Execute(GetTree query)
        {
            return _context.Trans
                .Where(x => 
                    _context.Trees
                        .Where(z => z.Id == query.TreeId)
                        .Union
                        ( _context.Trees
                            .Where(z => z.Id == query.TreeId)
                            .SelectMany(z => z.Children)
                        ).Select(z => z.Id)
                    .Any(q => x.Entity == $"{q}tree"))
                    .ToList();
        }
    }

Esecuzione (nel livello di servizio)

    var result = new TreesTransQuery(_context).Execute(query);

dove "query" è un'istanza della classe GetTree che è di seguito:

public class GetTree
{
    public int TreeId { get; set; }
}

Funziona bene, ma non sono sicuro che questa soluzione sia corretta. Quali dovrebbero essere esattamente le classi GetTree e TransTreeQuery?

Suppongo che TransTreeQuery sia l'implementazione della query, ma che dire di GetTree? Questa classe rappresenta i parametri per la query, quindi come dovrei chiamare questa classe? GetTreeParams? TreeTransQueryParams?

TreeTransQuery - implementazione della query

GetTree -?

    
posta bielu000 20.09.2017 - 08:19
fonte

2 risposte

2

Secondo me è una cattiva idea.

Per prima cosa prendi in considerazione la denominazione. TransTreeQuery contiene la logica per il recupero di un elenco di Trans. Essenzialmente si tratta di un repository e la tua interfaccia IQuery lo rende un repository generico.

Un modello di query, a mio avviso, è ciò che si ha con il linq nel metodo di esecuzione. Permette al chiamante di definire la query piuttosto che avere una serie di query predefinite che possono essere eseguite.

Ora, un repository generico è considerato negativo perché non può esporre i nomi dei metodi di tipo. Tutte le tue operazioni sono ora chiamate Get () o Aggiungi () o nel tuo caso Execute ().

Si evita questo problema avendo un solo metodo per classe, quindi è possibile utilizzare il nome della classe per indicare la funzionalità. Ma è difficile vedere come sarà usato in un'applicazione. Li raccoglierai in un ITransRepository con più metodi denominati? perché preoccuparsi dell'interfaccia in quel caso? Il passaggio di più oggetti di query attorno all'app aumenterà notevolmente la sua complessità.

Anche il pattern Query (come nel tuo Linq) è considerato negativo perché tende a collegarti all'implementazione del database sottostante. Le query che scrivi nei tuoi oggetti di query astratti potrebbero non essere performanti o addirittura eseguibili su tutti i database, quindi finirai per collegare il codice dell'applicazione (dove la query è definita) al linguaggio di query del database.

In conclusione, il modello proposto sembrerebbe essere un deposito che racchiude repository generici che racchiudono un repository interrogabile.

Scambierà Metodi e parametri per le Classi. Mentre questo dividerà la logica del repository su più sottoclassi rendendola potenzialmente più leggibile, avrai a disposizione decine di classi extra da gestire.

Sembra che questo obiettivo possa essere raggiunto in altri modi. Perdi l'interfaccia e la classe parametro, ad esempio, e mantieni la classe 'Query' interna al Repository. Forse può anche avere un metodo statico?

    
risposta data 20.09.2017 - 12:12
fonte
0

La soluzione è corretta. TransTreeQuery è il gestore della query GetTree . Può utilizzare l'ORM direttamente o tramite un'astrazione (repository). GetTree è un oggetto parametro . È possibile aggiungere un parametro di questo tipo all'azione del controller che riceve la query e fare in modo che il framework associ i parametri di richiesta alle proprietà di questo oggetto.

Di solito, le query e i loro gestori dovrebbero condividere una parte del loro nome. Potresti avere qualcosa come TransTreeQuery (invece di GetTree ) e TransTreeQueryHandler (invece di TransTreeQuery ). Lo stesso vale per i comandi.

    
risposta data 20.09.2017 - 09:27
fonte

Leggi altre domande sui tag