La superficie del livello di accesso ai dati deve restituire oggetti di trasferimento dati o restituire modelli EF?

1

Quindi, dire che ho un metodo di controllo

    // GET: TimeEntries
    [HttpGet("[action]")]
    public IEnumerable<TimeEntryDTO> GetLast(int value)
    {
        return dal.GetLast(value);
    }

E un metodo per il livello di accesso ai dati di (utilizzando AutoMapper per convertire TimeEntry in TimeEntryDTO)

    public IEnumerable<TimeEntryDTO> GetLast(int value)
    {
        return db.TimeEntries.TakeLast(value).ProjectTo<TimeEntryDTO>();
    }

La mia domanda è: devo fare questo e avere il DAL (Data Access Layer) restituire il DTO (Data Transfer Object) o dovrei avere il DAL restituire un IQuerable del modello EF e poi convertirlo in un DTO in il metodo del controller?

EDIT:

Dopo aver fatto qualche altra lettura, i DBset non sono esposti da un contesto EF, infatti, la superficie del repository? Quindi non vedresti mai il vero DAL vero, perché è uno strato all'interno di EF? Quindi non dovrei chiamare un layer che si trova in cima al contesto EF, un DAL?

    
posta TheColonel26 28.11.2018 - 15:08
fonte

3 risposte

3

...should I have the DAL return an IQuerable of the EF Model...

Per favore, non farlo. Come spiega Mark Seemann in IQueryable is Tight Coupling , questa interfaccia soffre di una serie di problemi.

  1. È ciò che viene spesso definito "interfaccia di intestazione". Questo termine si riferisce alla cattiva pratica in linguaggi come C in cui un file .h semplicemente descrive tutte le funzioni pubbliche trovate nel corrispondente file .c . Nessuna considerazione viene data alle esigenze del consumatore, semplicemente ottengono tutto in un unico grumo. Ciò significa che IQuerable è un'interfaccia enorme che è incredibilmente difficile da deridere quando si scrivono i test unitari sui metodi che lo restituiscono. Dai un'occhiata alla serie di 16 parti su come scrivi un'implementazione di IQuerable per avere un'idea di quanto possa essere difficile .

  2. È un'astrazione che perde. È effettivamente un'interfaccia scritta per riflettere il design di Entity Framework ORM. In quanto tale, espone gran parte del design funzionale di quell'ORM nell'interfaccia, ovvero quei dettagli di implementazione "filtrano" attraverso l'interfaccia. Pertanto, esponendo IQuerable nella tua API DAL, accoppi il tuo DAL e accoppi i consumatori di tale API.

L'intero scopo delle astrazioni è disaccoppiare parti del tuo codice. L'utilizzo di un'interfaccia che accoppia effettivamente le cose, sconfigge l'intero scopo di un'astrazione. Quindi non farlo.

Piuttosto, rispetta il tuo altro suggerimento: converti i dettagli di implementazione di IQuerable in DTO che sono focalizzati sulla fornitura di ciò di cui ha bisogno il chiamante. Ciò richiede un po 'più di lavoro in quanto è necessario scrivere i DTO e il codice di conversione, ma paga dividendi per tenere le cose disaccoppiate e più facili da capire e testare.

    
risposta data 29.11.2018 - 12:31
fonte
1

Dovresti eseguire il mapping su DTO nel repository e restituire il DTO da lì.

Questo è particolarmente utile quando si utilizza un progetto API Controllers separato, un progetto Data Layer separato, un progetto Repositories separato e un progetto DTO separato.

In questo modo il progetto Repositories dipende dal progetto Data Layer e dal progetto DTOs mentre il progetto che contiene i controller API dipende solo dalle interfacce (utilizzando l'iniezione di dipendenza) e dal progetto DTO e non ha conoscenza dei progetti Data Layer o Repository.

Crea un grafico delle dipendenze molto più semplice e pulito e una maggiore separazione delle preoccupazioni.

    
risposta data 28.11.2018 - 15:55
fonte
1

Sono d'accordo con @Dom e vorrei approfondire l'importanza di avere un progetto separato per i tuoi DTO. Di recente, in una delle nostre applicazioni, abbiamo deciso di interrompere l'uso di EF e di utilizzare Dapper. L'unica cosa che dovevamo cambiare è l'implementazione DAL (DAL.EF e ora abbiamo DAL.Dapper) che restituisce esattamente gli stessi DTO del progetto EF. Stiamo cambiando il codice e le implementazioni dove fa più male su base on-demand.

Se all'inizio avessimo deciso di iniettare semplicemente DbContext attraverso l'applicazione, dovremmo scrivere di nuovo tutto da zero.

    
risposta data 29.11.2018 - 22:58
fonte

Leggi altre domande sui tag