Inside ModelVirtualCasting #2: Architettura interna dei repository

di Marco De Sanctis, in Architettura,

Secondo post della serie sugli internals di ModelVC che abbiamo presentato a Real Code Day 4.0 prima e successivamente a Real Code Conference 4.0.

  1. Introduzione ai repository
  2. Architettura interna dei repository
  3. more to come...

La volta scorsa abbiamo visto perché abbiamo scelto di utilizzare i repository all'interno di ModelVC e abbiamo dato una panoramica dell'architettura secondo cui funzionano, che essenzialmente li porta ad essere dei wrapper degli ObjectSet di ADO.NET Entity Framework con qualche funzionalità in più. Semplificando un po', allora, il codice di un repository può essere pensato simile al seguente:

public class Repository<T> where T : class 
{ 
    private IObjectSet<T> objectSet; 
 
    public Repository(ObjectContext context) 
    { 
        this.objectSet = context.CreateObjectSet<T>(); 
    } 
 
    internal Repository(IObjectSet<T> objectSet) 
    { 
        this.objectSet = objectSet; 
    } 
 
    public void InsertOnSubmit(T entity) 
    { 
        this.objectSet.AddObject(entity); 
    } 
 
    public void Update(T entity) 
    { 
        this.objectSet.Attach(entity); 
    } 
 
    public IQueryable<T> Where(Expression<Func<T, bool>> predicate) 
    { 
        return this.objectSet.Where(predicate); 
    } 
}

Notiamo un paio di aspetti interessanti, che ci semplificano tanto la vita in fase di test:

  • Non manteniamo alcun riferimento a tipi concreti di ADO.NET Entity Framework, che è presente solo con l'interfaccia IObjectSet<T>;
  • E' presente un costruttore internal tramite cui fornire direttamente un IObjectSet, che può essere utilizzato per iniettare un mock o un fake.

Ottimo, sarebbe tutto bellissimo se non fosse che purtroppo per le funzionalità che vogliamo esporre, la sola IObjectSet<T> non basta: esempio? il metodo Include, che vogliamo utilizzare per indicare ad EF quali entity collegate deve caricare, è esposto da ObjectSet<T> (e anche da ObjectQuery, sua classe base) ma non dall'interfaccia. Come fare allora? Io e Stefano ci abbiamo riflettuto un po' e alla fine ne siamo venuti a capo in questo modo:

image

In pratica abbiamo introdotto le nuove interfacce IObjectQuery<T> e IIncludeObjectSet<T>, che espongono il metodo Include come desiderato; in particolare quest'ultima è referenziata all'interno di Repository<T> al posto di IObjectSet<T>, così che finalmente abbiamo a disposizione la funzionalità richiesta.

In Entity Framework, però, ObjectSet<T> ovviamente non implementa IIncludeObjectSet<T>, e pertanto siamo stati costretti a realizzarne un wrapper. Si tratta di un giro un po' complicato se vogliamo (tra l'altro la versione che trovate su ModelVC è leggermente più complessa) ma che fondamentalmente ci consente di costruire repository senza avere riferimenti a tipi concreti di Entity Framework. A cosa serve? a darci la possibilità di realizzare un FakeObjectSet, che trovate in ASPItalia.ModelVirtualCasting.MVC.Tests nella cartella Utils, che possiamo utilizzare per verificare che il nostro repository funzioni senza scomodare SQL Server:

var list = new List<User>(); 
list.Add(new User() { Nick = "Cradle"}); 
 
var rep = new UserRepository(new FakeObjectSet<User>(list)); 
Assert.AreEqual(list[0], repo.GetByNickname("Cradle"));

Cool, isn't it? Alla prossima!

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Nella stessa categoria
I più letti del mese