EF4 Code First, MVC2 y Unity para atarlo todo un poco…

Buenas! No soy ni mucho menos un experto en EF (es más, me acabo de poner), como pueda serlo p.ej. Unai, pero desde que Scott Guthrie publicó un post sobre EF Code First he empezado a mirar algunas cosillas.

Resumiendo rápidamente EF Code First nos permite desarrollar nuestra capa de acceso a datos codificando primero las clases, clases que son POCO. Eso nos permite conseguir lo que se conoce como persistance ignorance (o que las clases que nos representan los datos sean agnósticas sobre cualquier tecnología de acceso a datos).

Que quede claro que Code First no es la única manera de usar objetos POCO en EF: Unai y Alberto hablan del tema aquí y aquí. Y dad por seguro que ellos conocen EF mucho más que yo 🙂

Lo que os quiero comentar es como se puede montar EF Code First en una aplicación MVC2 para poder usar el patrón Repository y Unit Of Work, de forma que los controladores no deban saber nada del mecanismo subyacente de acceso a datos (es decir, los controladores ignoran completamente que están usando EF).

1. Rápida, rapidísima introducción a EF Code First

Usar EF Code First es muy sencillo. En el post de Scott Guthrie está todo explicado paso a paso, pero resumiendo podríamos decir que me puedo crear una clase tal que:

public class Persona
{
public int PersonaId {get; set;}
public string Nombre {get; set;}
}

Esta clase nos permitiría acceder a datos almacenados en una tabla con los campos PersonaId y Nombre (EF Code First es capaz de crear la BBDD a partir del modelo de objetos). Para acceder a la bbdd creamos un objeto derivado de DbContext:

public class MyDatabase : DbContext
{
public DbSet<Persona> Personas {get; set;}
}

Y a partir de aquí instanciamos un objeto MyDatabase y lanzamos consultas linq contra la propiedad Personas… 🙂

2. Patrón repositorio y Unit of work

Esos patrones están explicados por activa y por pasiva en muchos sitios. P.ej. aquí está el patrón repositorio y aquí el Unit of Work (UoW). Básicamente entendemos que el repositorio es una colección de objetos en memoria y que el patrón UoW sincroniza todos los cambios hechos en memoria hacia la base de datos.

Supongamos estos dos interfaces para definir ambos patrones:

public interface IRepository<TEntity> where TEntity : class
{
IQueryable<TEntity> AsQueryable();
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> where);
}

public interface IUnitOfWork
{
void Commit();
}

Mi repositorio es de sólo lectura (no hay métodos Add ni Remove ni nada, pero todo es añadirlos) y el Unit of Work lo único que tiene es el método Commit() para sincronizar los cambios hechos en los repositorios y mandarlos todos a la base de datos.

EF Code First, implementa de per se el patrón Unit Of Work (a través de DbContext) y también el patrón repositorio a través de DbSet<>, pero recordad que yo quiero “agnostizarme” al respecto de EF, por eso creo las interfaces y ahora debo crear implementaciones de ellas para EF:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private IDbSet<TEntity> _dbSet;

public Repository(IDbContext objectContext)
{
_dbSet = objectContext.Set<TEntity>();
}
public IQueryable<TEntity> AsQueryable()
{
return _dbSet;
}
public IEnumerable<TEntity> GetAll()
{
return _dbSet.ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> where)
{
return _dbSet.Where(where);
}
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly IDbContext _objectContext;

public UnitOfWork(IDbContext objectContext)
{
_objectContext = objectContext;
}

public void Dispose()
{
if (_objectContext != null)
{
_objectContext.Dispose();
}
GC.SuppressFinalize(this);
}

public void Commit()
{
_objectContext.SaveChanges();
}
}

La única “complicación” es en la implementación de UnitOfWork, que en el constructor uso un objeto de tipo IDbContext, pero esta interfaz no existe en EF: me la he inventado yo, para poder realizar DI luego cuando use Unity. La interfaz IDbContext es muy simple:

public interface IDbContext : IDisposable
{
IDbSet<T> Set<T>() where T : class;
int SaveChanges();
}

Me permite obtener un IDbSet de entidades de tipo T y el método SaveChanges para persistir los cambios realizados en este contexto hacia la BBDD.

3. Uso de todo esto…

Para usar directamente un repositorio me basta con instanciarlo, pasándole como parámetro el IDbContext. Pero recordad que la clase DbContext de EF Code First no implementa IDbContext (que me lo he inventado yo), así que uso el patrón Adapter para traducir los objetos DbContext a IDbContext:

public class DbContextAdapter : IDbContext
{
private readonly DbContext _context;
public DbContextAdapter(DbContext context)
{
_context = context;
}
public void Dispose()
{
_context.Dispose();
}
public IDbSet<T> Set<T>() where T : class
{
return _context.Set<T>();
}
public int SaveChanges()
{
return _context.SaveChanges();
}
}

Ahora sí que ya puedo crear un repositorio:

IDbContext ctx = new DbContextAdapter(MyDatabase);  // MyDatabase deriva de DbContext
var rep = new Repository<Persona>(ctx);
var personas = rep.FindAll();

Para usar el Unit of Work vinculado a un contexto haríamos lo mismo.

4. Añadiendo IoC a todo esto…

Ahora que ya vemos como podemos usar nuestro repositorio, vamos a ver como Unity nos ayuda a tener IoC y independizarnos realmente de EF.

Primero podríamos registrar las implementaciones concretas de IRepository y IUnitOfWork:

// Container es el IUnityContainer
Container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
Container.RegisterType<IUnitOfWork, UnitOfWork>();

Ahora debemos mapear IDbContext a DbContextAdapter (porque para instanciar tanto IRepository como IUnitOfWork les debemos pasar un IDbContext. Podríamos usar lo siguiente:

Container.RegisterType<IDbContext, DbContextAdapter>();

Este RegisterType está bien, pero el problema nos viene cuando vemos que el constructor de DbContextAdapter tiene un objeto DbContext. Eso significaría que Unity nos crearía un objeto de la clase DbContext y no de la clase derivada MyDatabase, para instanciar los objetos DbContextAdapter. Nota: Una solución sería que la clase DbContextAdapter tuviese en su constructor un objeto que no fuera DbContext sinó MyDatabase pero eso entonces limita la reutilización de todo lo que estamos haciendo!

Por suerte no estamos perdidos! Unity incorpora un mecanismo mediante el cual le podemos decir como crear un objeto de una determinada clase. En mi post sobre Unity 2.0, hablé de las Injection Factories. La idea es decirle a Unity que cuando necesite un objeto de la clase indicada, en lugar de crearlo tal cual use una factoría nuestra.

Es decir podemos hacer una factoría para crear DbContext que en lugar de un DbContext devuelva un MyDatabase, y Unity usará dicha factoría cada vez que deba crear un DbContext:

Container.RegisterType<DbContext>(new InjectionFactory(x => new MyDatabase()));

Listos! Con esto cuando Unity deba pasar a DbContextAdapter un objeto DbContext (como indica el constructor) creará realmente un objeto MyDatabase.

Ahora si que ya puedo hacer:

var rep = Container.Resolve<IRepository<Persona>>();

5. Y finalmente… MVC2

Para integrar esto dentro de MVC2 es muy sencillo: como siempre que queramos inyectar IoC en los controladores lo que debemos tocar es… la factoría de controladores:

public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer _sl;

public UnityControllerFactory(IUnityContainer sl)
{
_sl = sl;
}

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
IController controller = _sl.Resolve(controllerType);
return controller;
}
}

Y como siempre establecerla en el Global.asax:

UnityControllerFactory slcf = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(slcf);

Y listos! Ahora si que hemos llegado al punto final. Por fin podemos declarar un controlador tal que:

public class PersonasController : Controller
{
private IRepository<Persona> _rep;

public HandController(IRepository<Persona> rep)
{
_rep = rep;
}
}

Y empezar a trabajar usando el repositorio! 🙂

Fijaos que en este punto (el controlador) no tenemos nada que nos ate a EF: el repositorio es una interfaz y las clases que usa el repositorio son objetos POCO.

6. Y para terminar (pero NO lo menos importante)…

Cuando trabajamos con aplicaciones web, es recomendable que los contextos de base de datos tengan una duración (lifetime) de request (se les llama objetos per-request): es decir si durante una misma petición se necesitan dos repostorios, estos dos repositorios deben de compartir del contexto de base de datos. Con lo que tenemos ahora no sucede esto, ya que cada vez que Unity deba crear un Repository<> creará su DbContextAdapter asociado que a su vez creará un DbContext (MyDatabase) nuevo. Ese comportamiento no es el desado.

Por suerte Unity tiene un mecanismo muy bueno para poder establecer cada cuando debe el contenedor crear un objeto de un tipo determinado: los lifetime managers. Una solución es crearse un HttpRequestLifetimeManager, de forma que los objetos sólo persistirán durante la misma petición y usar este lifetime manager cuando hagamos el RegisterType de DbContext.

En http://unity.codeplex.com/Thread/View.aspx?ThreadId=38588 tenéis una implementación de un HttpRequestLifetimeManager, junto con una interesante aportación sobre el uso (en su lugar) de contenedores hijos que mueran a cada request, que tengan los objetos registrados como singletons y eliminar el contenedor hijo (con Dispose()) al final de cada request. Esto tiene la ventaja de que se llamaría a Dispose() de los objetos contenidos (en esta segunda aproximación es el contendor hijo el que tiene un ciclo de vida per-request).

7. Referencias

Los siguientes posts contienen más información al respecto:

  1. Entity Framework POCO (EF4): Generic Repository and Unit of Work Prototype. Este es el post que me ha servido de inspiración y de ayuda. Tiene una continuación (Unity Extension for Entity Framework POCO Configuration, Repository and Unit of Work) donde comenta el uso de Unity. Estos dos posts son de lectura imprescindible, aunque por un lado haya tenido que modificar algunas cosillas para que funcione con la CTP4 de EF Code first y por otro en el tercer post utilize una StaticFactoryExtension en lugar de una Injection Factory (supongo que usa Unity 1.2 que no soporta Injection Factories). Este tercer post utiliza una aproximación genial que es el uso de una extensión de Unity para configurar todos los mappings para los objetos de EF. Repito: lectura imprescindible.
  2. Los posts de Scott Guthrie sobre EF Code First:
    1. http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx
    2. http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx
    3. http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx

Un saludo!!! 🙂

11 comentarios sobre “EF4 Code First, MVC2 y Unity para atarlo todo un poco…”

  1. Excelente post Eduard 🙂 con detalles arquitecturales de primer orden.

    Unit of Work, Repository, Factory, Adapter, IoC y DI… sabes lo que me preocupa de toda esta cantidad de patrones en un post como este?

    Que exista el riesgo de que no se distinga que ni pertenecen ni tienen nada que ver con MVC ni con EF, sino que son patrones de diseño de software, abstracciones.

    Evidentemente tú ahí no tienes nada que ver, sólo es una reflexión en alto que siempre me preocupa de los posts sobre tecnologías concretas que tratan con conceptos más abstractos también. Lo curioso, y no demasiado bueno a veces, es que la gente descubre 5 patrones porque se los trajo una tecnología y creen que Lazy Loading es un concepto de EF, no que es algo abstracto y mas viejo que andar para adelante.

    Este es un post excelente para apreciarlo por el trabajo con abstracciones y una aplicación práctica de las mismas que propone, espero que se lea así e incluso despierte algún interés por ahondar en qué es aquello de un patrón creacional o qué problema resuelve, por qué existe y para que sirve un Unit of Work o es que se inventó ayer con EF, etc.

    Gran post 🙂

  2. @José
    Muchas gracias por tu comentario!
    Tienes toda la razón en lo que dices. Pero por si acaso vamos a recalcarlo de nuevo: efectivamente todos esos patrones NADA tienen que ver ni con MVC, ni con EF…

    Usar EF ha sido simplemente una opción tecnológica, y usar MVC ha sido, por un lado porque me encanta y por otro porque simplemente, me permite dar un sentido final al post: crear controllers totalmente agnósticos del acceso a datos. Pero cierto: los mismos patrones aplican a webforms, winforms, wpf, etc, etc, etc.
    De ahí que haya puesto los enlaces al onmipresente Martin Fowler o a la Wikipedia: para que se vea que esos patrones no son «propiedad» de MVC, EF, ni de Microsoft… 🙂

    @Alberto, José
    Muchas gracias! Ya os diré que tal: ahora estoy en la fase «que chulo que es EF Code first». Dentro de dos días cuando el enamoramiento se disipe al salir las primeras dificultades serias, veremos lo que hago: si me tiro directamente al whisky o me quedo en las cervezas! 🙂

    @Javier
    El código «completo» es parte de un proyecto con bastante más código que haría bastante dificil ver lo que queria contar en el post. De todos modos voy a recotarlo y colgar el código sólo con lo justo, aunque voy a tardar un par de días 🙂
    Ya avisaré en cuando cuelgue el código!

    Gracias de nuevo por todos los comentarios! 😀

  3. Eduard, como todo el mundo te da cancha yo me voy a ponre en plan criticón ¿vale?. Aunque en el fondo me gusta bastante la aproximación la verdad es que la implementación tiene un par de cosillas que me gustaría comentar, aunque entiendo que más que tuyo viene de las referencias que comentas que te han servido como inspiración. En primer lugar la clase ContextAdapter no tiene una responsabilidad clara en cuanto a su necesidad puesto que podrías inyectar directamente un IContext, incluso aunque esto no fuera Code First puesto que podrías tocar la plantilla. Despues, el UoW tiene una dependencia con quien no debería tenerla, es decir, es tu contexto de trabajo el que es un UoW no al raves, yo haría que IContext fuera tu UoW implementando esa interface, pero esto es un poco de gustos…

    Ahora, con respecto a un ejemplo de estos patrones aplicados con un cliente MVC aunque hay muchos me permito recomendar la guia de arquitectura que microsoft españa tiene en su site de arquitectura y el correspondiente proyecto en codeplex,
    http://microsoftnlayerapp.codeplex.com/

    Saludos
    Unai

  4. @Unai
    Muchas gracias por tu comentario! Si has leído el post ya debes saber que te considero un referente en EF en españa 🙂

    MMMmm… lo que comentas sobre ContextAdapter, sirve para poder inyectar un DbContext en los repositorios: estos dependen de IDbContext, no de DbContext de forma directa.
    Un objetivo perseguido es que los repositorios no tengan dependencia directa con EF.

    Sobre lo de UoW voy a echarle un vistazo!!!

    Un saludo y gracias por comentar!

  5. Eduard, gracias por lo primero. No obstante, entiendo perfectamente el proposito del Adapter pero no en este contexto, es decir, un adaptador te permite «adaptar» un contrato a otro, pero tiene sentido cuando tu no eres el creador del primero. Ahora, en tu ejemplo si haces Code First, o incluso con plantillas, tu eres el creador del contrato, es decir, nadie te impide hacer un contrato como IContext, por ejemplo y hacer que tu contexto de trabajo de code first lo implemente. Con esto, puedes inyectar en tu repositorio directamente IContext, ya garantizas Persistence Ignorant, y te libras de tener un adaptador bailando que no aporta nada y su responsabilidad es vacia cuando tu eres el dueño del codigo,. Espero haberme explicado bien, si no lo podemos poner más en claro con un ejemplo 🙂

  6. @Unai
    Gracias por responder!

    Te entiendo, te entiendo… Te refieres a que mi propio contexto («MyDatabase» en el post) implemente IContext.
    Tan elemental que no veo porque no lo vi en tu primer comentario!
    El uso del adapter viene como dices de las referencias que he usado. En este caso no se atan a una clase derivada de DbContext, usan DbContext directamente por lo que necesitan el adapter. Pero efectivamente, tienes razón: en mi ejemplo es totalmente redundante.

    Ya para completar el comentario:
    Intenté que la implementación de los repositorios fuese agnóstica de EF, puesto que créia que podía lanzar las queries directamente contra IQueryable sin problemas. Funciona bien para queries «generales», pero obviamente llega un momento en que debes hacer uso de capacidades de EF en los repositorios (p.ej. Include()), así que al final la implementación de los repositorios es dependiente de EF (la interfaz no claro, porque forma parte del dominio).

    Un saludo!

  7. Si, el Include es una de las cosas que tienes que manejar con cuidado, no solamente aquí sino también en testeo que para hacer un mimic es puñetero. Es darme algo de cancha pero puedes mirar
    microsoftnlayer.codeplex.com puesto que estas cosas ya están implementadas…
    Saludos
    Unai

  8. Eduard / Unai

    He leido con interes sus cruces de ideas y me parece que vale la pena plasmarlas en un nuevo ejemplo que las contenga.

    Tambien me parece que seria bueno que ese nuevo ejemplo utilice un archivo de configuracion para IoC en vez de hacerlo por codigo porque no hay buenos ejemplos en la red de inyeccion de constructores.

    Ojala puedan hacerlo!!

    Muchas, muchas gracias
    Pablo

Responder a etomas Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *