Restituire un IQueryable da un IRepository

8

Utilizzando il modello di repository, è corretto restituire un IQueryable di un set di dati (tabella), per l'utilizzo generico?

In molti casi è molto utile, specialmente quando si utilizzano librerie esterne che sfruttano tale interfaccia, ad esempio alcuni plugin che ordinano / filtrano e si collegano agli elementi dell'interfaccia utente.

Tuttavia, l'esposizione di un IQueryable a volte sembra lasciare il design incline agli errori. Questo, insieme a un utilizzo errato del caricamento lento, potrebbe causare gravi risultati in termini di prestazioni.

D'altro canto, avere metodi di accesso per ogni singolo utilizzo sembra ridondante e anche molto lavoro (considerando i test unitari ecc.)

    
posta Mihalis Bagos 27.08.2012 - 09:54
fonte

2 risposte

12

Mark Seemann ha un eccellente post sul blog su questo argomento: IQueryable è Tight Coupling . Lo riassume bene nella parte finale (sottolineatura mia):

You may think this is all a theoretical exercise, but it actually does matter. When writing Clean Code, it's important to design an API in such a way that it's clear what it does.

An interface like this makes false guarantees:

public interface IRepository
{
    IQueryable<T> Query<T>();
}

According to the LSP and Postel's law, it would seem to guarantee that you can write any query expression (no matter how complex) against the returned instance, and it would always work.

In practice, this is never going to happen.

Programmers who define such interfaces invariably have a specific ORM in mind, and they implicitly tend to stay within the bounds they know are safe for that specific ORM. This is a leaky abstraction.

If you have a specific ORM in mind, then be explicit about it. Don't hide it behind an interface. It creates the illusion that you can replace one implementation with another. In practice, that's impossible. Imagine attempting to provide an implementation over an Event Store.

The cake is a lie.

Le implementazioni di ORM come Entity Framework sono del Repository e del modello dell'Unità di lavoro. Non è necessario avvolgerli in un altro.

    
risposta data 27.08.2012 - 13:37
fonte
1

Non ci sarà consenso su questo. Secondo la mia opinione ed esperienza, un deposito dovrebbe restituire oggetti con usi specifici. Al leas se si utilizza Pattern di deposito come definito da Eric Evens in DDD. Un repository è un "ponte" che collega la logica aziendale, la persistenza e le fabbriche.

Se desideri accedere più direttamente alla persistenza, forse stai cercando il Gateway Pattern.

Tuttavia, da quello che dici qui, ti piacerebbe nascondere quell'esposizione alla persistenza in modo che il Proxy Pattern possa essere utile per te.

    
risposta data 27.08.2012 - 13:28
fonte