è una cattiva pratica che il repository delle chiamate del controller invece del servizio?

26

è una cattiva pratica quella repository di call del controller invece del servizio?

per saperne di più:

Capisco che nei buoni controllori di progettazione chiamano il servizio e il servizio utilizzano il repository.

ma a volte nel controller non ho / ho bisogno di alcuna logica e ho solo bisogno di recuperare da db e passarlo alla vista.

e posso farlo semplicemente chiamando il repository - non c'è bisogno di chiamare il servizio - è una cattiva pratica?

    
posta mohsenJsh 08.01.2016 - 18:22
fonte

2 risposte

17

No, pensa in questo modo: un repository è un servizio (anche).

Se le entità che si recuperano attraverso il repository gestiscono la maggior parte della logica aziendale, non sono necessari altri servizi. È sufficiente avere il repository.

Anche se hai alcuni servizi che devi passare per manipolare le tue entità. Prendi prima l'entità dal repository e poi passa a detto servizio. Essere in grado di lanciare un HTTP 404 prima ancora di provarlo è molto conveniente.

Anche per gli scenari di lettura è normale che ti serva solo l'entità per proiettarlo su un DTO / ViewModel. Avere un livello di servizio intermedio spesso comporta un notevole passaggio di metodi piuttosto brutti.

    
risposta data 08.01.2016 - 22:25
fonte
0

Non è una cattiva pratica per un controller chiamare direttamente un repository. Un "servizio" è solo un altro strumento, quindi usalo dove ha senso.

NikolaiDante ha commentato:

... Pick the right pattern for the right application. What I would say is that you should make your application consistent.

Non penso che la coerenza sia l'aspetto più importante. Una classe "service" ha lo scopo di incapsulare alcune logiche di livello superiore in modo che il controller non debba implementarlo. Se non è richiesta una "logica di livello superiore" per una determinata operazione, vai direttamente al repository.

Per promuovere il bene Separate of Concerns e testability, il repository dovrebbe essere una dipendenza che si inserisce nel servizio tramite un costruttore:

IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);

service.DoSomething(...);

Se la ricerca di record nel database richiede una sorta di query con parametri, una classe di servizio potrebbe essere un buon posto per prendere il tuo modello di vista e creare una query che viene poi eseguita dal repository.

Allo stesso modo, se si dispone di un modello di vista complesso per un modulo, una classe di servizio può incapsulare la logica di creazione, aggiornamento ed eliminazione di record chiamando metodi sui propri Modelli / Entità di Dominio, quindi persistendoli utilizzando un repository.

Andando nella direzione opposta, se il tuo controller ha bisogno di ottenere un record con il suo ID, delegare a un oggetto di servizio è come colpire una puntina con un martello: è molto più del necessario.

Ho trovato che il controller è nella posizione migliore per gestire la transazione, o un Oggetto Unità di lavoro . Il controller o l'oggetto Unit Of Work delegherebbe quindi agli oggetti di servizio per operazioni complesse, o andrà direttamente al repository per operazioni semplici (come trovare un record con Id).

public class ShoppingCartsController : Controller
{
    [HttpPost]
    public ActionResult Edit(int id, ShoppingCartForm model)
    {
        // Controller initiates a database session and transaction
        using (IStoreContext store = new StoreContext())
        {
            // Controller goes directly to a repository to find a record by Id
            ShoppingCart cart = store.ShoppingCarts.Find(id);

            // Controller creates the service, and passes the repository and/or
            // the current transaction
            ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);

            if (cart == null)
                return HttpNotFound();

            if (ModelState.IsValid)
            {
                // Controller delegates to a service object to manipulate the
                // Domain Model (ShoppingCart)
                service.UpdateShoppingCart(model, cart);

                // Controller decides to commit changes
                store.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }
    }
}

Penso che un mix di servizi e lavorare direttamente con gli archivi sia perfettamente accettabile. Potresti incapsulare ulteriormente la transazione in un oggetto Unit Of Work se ne hai sentito il bisogno.

La ripartizione delle responsabilità è la seguente:

  • Il controller controlla il flusso dell'applicazione
    • Restituisce "404 non trovato" se il carrello acquisti non si trova nel database
    • Ri-rende il modulo con i messaggi di convalida se la convalida fallisce
    • Salva il carrello degli acquisti se tutto viene eliminato
  • Il controllore delega a una classe di servizio per eseguire la logica di business sui tuoi modelli di dominio (o entità). Gli oggetti servizio dovrebbero non implementare la logica aziendale! Loro eseguono la logica aziendale.
  • I controllori possono delegare direttamente ai repository per operazioni semplici
  • Gli oggetti servizio acquisiscono i dati nel modello di visualizzazione e delegano ai modelli di dominio per eseguire la logica aziendale (ad esempio, l'oggetto servizio chiama i metodi sui modelli di dominio prima di chiamare i metodi nel repository)
  • Gli oggetti servizio delegano agli archivi per la persistenza dei dati
  • I controller dovrebbero:
    1. Gestisci la durata di una transazione, o
    2. Crea un oggetto Unit Of Work per gestire la durata di una transazione
risposta data 08.01.2016 - 20:13
fonte

Leggi altre domande sui tag