Confuso su come utilizzare correttamente un modello di repository con Service / Business Layer in cima

5

Sto costruendo una soluzione ASP.NET Web Api 2 per scopi di apprendimento, e ho avuto un problema. Mi stavo chiedendo se qualcuno potesse dirmi che cosa esattamente mi manca.

La soluzione My Web Api ha 4 livelli:

  • Dati, che contiene i modelli di dati (POCO), i fluidi mapping delle API, il contesto EF, le migrazioni e la semina
  • Repository, che implementa CRUD per tutti i modelli di dati e restituisce i modelli aziendali
  • Dominio / Servizio / Azienda che fornisce l'interfaccia IRepository e dovrebbe contenere servizi che implementano la logica di business dell'applicazione. Contiene anche i modelli aziendali.
  • Web, i controller Web Api e DI / IoC per legare tutto insieme.

I riferimenti sono i seguenti: Dati < Repository > Dominio

Il Web fa riferimento a tutti e 3 i livelli per DI.

L'idea dietro il livello di dominio separato è che è completamente ignaro di tutto ciò che accade nel livello Data o Repository. Delinea semplicemente i suoi requisiti fornendo l'IRepository per il livello di repository e i Business Models che desidera ottenere come risultato. Spetta al livello del repository soddisfare le richieste del livello del dominio.

Ecco il mio connundrum :

  • Poiché il dominio non ha legami con i dati, non conosce nulla sulla struttura del modello dati. Ciò significa che il livello del repository deve convertire tutto nel Business Model prima di restituirlo. - Suppongo di poterlo restituire come un oggetto generico e quindi associare l'oggetto generico al modello di business all'interno del Domain Layer. Sarebbe più appropriato?
  • Anche in questo caso, poiché il Dominio non sa nulla del Modello Dati, non posso passare nessuna espressione da applicare sul set di dati al mio Archivio. Ciò significa che per ogni proprietà che desidero DOVE, dovrei creare un repository specifico per POCO abbinato a IBussinessModelRepository che ne delinea i requisiti e quindi implementare tale requisito. Questo diventa presto tedio però, in quanto richiede un gruppo di "GetByProp1", "GetByProp2" - codice centrale scimmia.
  • Che cosa succede se voglio creare un modello aziendale composito che richiede una query complessa per idratare? La mia unica opzione è creare un altro repository di IB Business con un repository corrispondente e quindi scrivere la query complessa nel livello repository? In questo caso, sembra che il livello di servizio sia per lo più solo un altro passaggio che passa per richieste non crude a specifici repository.
  • È corretto per i controllori web api inviare richieste direttamente al repository? Sembrerebbe piuttosto sciocco instradare tutte le richieste CRUD attraverso il livello di servizio, che passa comunque la richiesta al livello di repository comunque. No, non è perché il livello di servizio dovrebbe essere il punto di ingresso per tutte le operazioni. (Con Web che agisce semplicemente come consumatore dei servizi offerti).
  • Al momento non utilizzo un'unità di lavoro perché ci sono molte opinioni contrastanti su Uow + EF. Non ho ancora abbastanza esperienza per stare da entrambi i lati del recinto. Sarebbe utile un UoW in questo scenario?

Mi sento come se mi mancasse una parte vitale in ciò che rende questo approccio pattern / layer tick.

So che potrei tranquillamente procedere con l'imbroglio (cioè dare accesso al servizio a cose specifiche come il contesto), ma sono più interessato a imparare come farlo nel modo giusto.

Le ricerche che ho svolto fino ad ora hanno prodotto risultati che variano enormemente:

  • Dal repository utilizzando AutoMapper per modificare il tipo nel modello di business senza eseguire effettivamente la query, consentendo al livello di servizio di superare le espressioni del modello aziendale che possono quindi essere applicate e quindi eseguendo la query, restituendo il risultato mappato - sembra ottimo , eccetto che l'approccio non sembra funzionare per me a causa di AutoMapper che non è in grado di gestire i miei modelli con proprietà di navigazione ricorsive.
  • Al livello di servizio che si interfaccia semplicemente direttamente con i POCO. (E quindi avere accesso diretto al DAL)

Cosa mi manca?

Modifica per ulteriori informazioni sul mio codice:

Il mio repository generico su Github contiene metodi CRUD come questo:

public abstract class RepositoryBase<TData, TDomain, TId> : IRepository<TDomain, TId> where TDomain : EntityBase<TId>, new() where TData : class, IDataEntity<TId>, new()
{
    private readonly ShortStuffContext _context;

    public RepositoryBase(ShortStuffContext context)
    {
        _context = context;
    }

    public IEnumerable<TDomain> GetAll()
    {
        return _context.Set<TData>().BuildQuery<TData, TDomain>();
    }
}

BuildQuery è un'estensione LINQ che afferra tutte le entità o può assumere un'espressione per recuperare una singola entità e quindi utilizza ValueInjecter per associare il modello di dati al modello di dominio.

I metodi del repository sono richiesti dal Domain Layer tramite l'interfaccia:

public interface IRepository<TDomain, TId> where TDomain : EntityBase<TId>
{
    IEnumerable<TDomain> GetAll();
}

RepositoryBase viene esteso dai repository per i singoli POCO, che attualmente si trovano vuoti, fornendo solo TData, TDomain e TId alla base del repository:

public class UserRepository : RepositoryBase<Data.Entities.User, User, decimal>
{
    public UserRepository(ShortStuffContext context)
        : base(context)
    {
    }
}

Che può essere richiesto dal livello del dominio tramite Iniezione del costruttore IRepository<User, decimal> UserRepository attraverso un vincolo di novice InRequestScope .

    
posta Bio2hazard 08.07.2014 - 03:12
fonte

1 risposta

1

Quanto è grande la tua applicazione? Ci sono buone possibilità che tu stia pensando troppo a questo. A meno che l'applicazione non sia un'applicazione di livello aziendale di grandi dimensioni, probabilmente non è necessario l'elevato grado di accoppiamento lento che si sta promuovendo.

Se si decide che questo livello di accoppiamento libero è ancora necessario, creare un livello di servizio che restituisca oggetti di "servizio". Questo svolge una funzione simile a Visualizza i modelli in MVC. Quindi scriverai il codice nel tuo livello di servizio che mappa gli oggetti dal tuo modello di dominio al tuo modello di servizio.

Nota che parte della tua lotta può essere dovuta al fatto che, mentre il tuo repository dati sta restituendo oggetti CRUD, il tuo livello di servizio dovrebbe restituire il risultato delle azioni. Ad esempio:

public InvoiceView GetInvoice(int invoiceID);

restituisce un oggetto InvoiceView contenente i dati che desideri esporre al pubblico, inclusi Nome, Indirizzo, Elementi pubblicitari e così via, da diverse tabelle / oggetti nel tuo dominio.

public class InvoiceView
{
    public int InvoiceID;
    public Address ShippingAddress;
    public Address BillingAddress;
    public List<LineItem> LineItems;
    ...
}

Allo stesso modo, ci saranno metodi Service Layer che eseguono semplicemente un'azione e restituiscono un oggetto che indica il risultato dell'azione:

public TransactionResult Transfer(
    int sourceAccountID, int targetAccountID, Money amount, ValidationToken token);

IMPORTANTE: Non sarai mai in grado di disaccoppiare completamente i dati. Il tuo consumatore dovrà sempre avere una certa conoscenza dei dati, anche se si tratta solo di un ID oggetto o UUID.

    
risposta data 08.07.2014 - 03:57
fonte

Leggi altre domande sui tag