Introducción Entity Framework 4.1 Code Firts

La versión 3.5 SP1 del framework .NET nos proveia de una biblioteca ORM llamada Entity Framework. Esta primera versión recibió varias criticas por parte de los desarrolladores, las cuales por suerte fueron escuchadas por el equipo de .NET. Es por este motivo que junto a la salida de .NET 4 apareció una versión mejorada llamada Entity Framework 4.1.

Entre las mejoras que se incluyen en esta nueva versión se encuentran: el manejo de clases POCO, soporte para Lazy Load, mejor calidad en las querys SQL generadas, mayor compatibilidad con Linq entre otras más.

En este post vamos a trabajar con una nueva caracteristica de EF llamada Code Firts (cuya traducción valida prodía ser “Partiendo del código“) y cuyo punto fuerte es que partiendo de nuestras clases del dominio ya podemos crear nuestro modelo ORM. Todo esto sin preocuparnos por la creación de la base de datos, el mapeo entre las entidades y la DB, los archivos XML o editores y todas las configuraciones afines.

Pero vayamos por parte, antes de comenzar con un ejemplo, vamos a crear un proyecto ASP.NET MVC 3 y agregar las referencias a esta librería. Para poder trabajar con EF 4.1 Code First antes vamos a tener que instalar el componente EFCodeFirst y podemos hacerlo de una manera muy sencilla utilizando Nuget (en la pestaña online\all buscamos dicho componente e instalamos).

Instalando EF4.1 desde Nuget

Instalando EF4.1 desde Nuget

Finalizada nuestra instalación se nos abrirá un archivo ReadMe con algunos comentarios sobre el producto y se habrán agregado a la solución los assemblies correspondientes.

El segundo paso sera crear las entidades del modelo, en este ejemplo vamos a trabajar con dos entidades muy simples, la primera representara una agenda y la segunda eventos de la misma. Estas clases a crear son objetos simples denominados POCO en el ambiente .NET (es importante que estas clases POCO respeten algunas convenciones que no son para nada complejas y que nos permitirán trabajar con EF).

Es el turno de definir las clases que compondran nuestro modelo:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }

1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Algo interesante a comentar de estas entidades es que las propiedades definidas como virtual corresponden a propiedades de navegación, y son aquellas que se pueden cargar en “diferido” (en otro post vamos a ver de que se trata esto).

El segundo paso será crear un contexto que nos permita realizar operaciones CRUD sobre nuestras instancias de Agenda y Evento. Para esto vamos a crear una clase llamada DatosContext que derive de DbContext y que contendra dos propiedades publicas (una por cada entidad del modelo que hemos creado) que seran del tipo DbSet<T>:

1: using System.Data.Entity;
2:
3: namespace MvcAndEF.Models
4: {
5:     public class DatosConext : DbContext
6:     {
7:         public DbSet<Agenda> Agendas { get ; set ; }
8:         public DbSet<Evento> Eventos { get ; set ; }
9:     }
10: }

Como ya se habran dado cuenta, estas librerias pertenecen a System.Data.Entity y son provistas por EF4.1. Las clases DbContext y DbSet nos permitiran realizar las operaciones relacionadas con el acceso a los datos.

A pesar de todo esto aún no hemos creamos la base de datos y mucho menos un mapeo con la misma, tampoco hemos utilizamos diseñadores y mucho menos realizamos configuraciones. Sin embargo ya estamos listo para trabajar! 🙂

Cómo es posible esto?… la respuesta es bastante sencilla, EF 4.1 Code First esta pensado para trabajar por convenciones en lugar de configuraciones (es por eso que al crear nuestras clases POCO tuvimos en cuenta ciertas consideraciones). El resto es historia conocida: cada clase se corresponderá con una tabla, cada propiedad una columna de la misma y cada instancia de dichas clases representará un registro en la base de datos.

Para ver en funcionamiento nuestro contexto, vamos a trabajar sobre un nuevo controlador llamado AgendaController y en las diferentes acciones armaremos consultas para persistir y recuperar los datos de nuestro modelo:

1: using System.Linq;
2: using System.Web.Mvc;
3: using MvcAndEF.Models;
4:
5: namespace MvcAndEF.Controllers
6: {
7:     public class AgendaController : Controller
8:     {
9:         DatosContext datos = new DatosContext();
10:
11:         public ActionResult Index()
12:         {
13:             var agendas = from a in datos.Agendas
14:                           select a;
15:
16:             return View(agendas.ToList());
17:         }
18:
19:         public ActionResult Create()
20:         {
21:             return View();
22:         }
23:
24:         [HttpPost]
25:         public ActionResult Create(Agenda model)
26:         {
27:             if (ModelState.IsValid)
28:             {
29:                 datos.Agendas.Add(model);
30:                 datos.SaveChanges();
31:
32:                 return RedirectToAction("Index");
33:             }
34:
35:             return View(model);
36:         }
37:
38:         public ActionResult Edit(int id)
39:         {
40:             var agenda = datos.Agendas.Single(a => a.AgendaId == id);
41:             return View(agenda);
42:         }
43:
44:         [HttpPost]
45:         public ActionResult Edit(Agenda model)
46:         {
47:             if(ModelState.IsValid)
48:             {
49:                 var agenda = datos.Agendas.Single
50:                             (a => a.AgendaId == model.AgendaId);
51:                 agenda.Propietario = model.Propietario;
52:                 agenda.FechaCreacion = model.FechaCreacion;
53:
54:                 datos.SaveChanges();
55:
56:                 return RedirectToAction("Index");
57:             }
58:
59:             return View(model);
60:         }
61:     }
62: }

En cada uno de los métodos de acción podemos observar ejemplos de las consultas básicas: selección, inserción y actualización de una entidad. Lo siguiente será crear cada una de las vistas para dichos métodos (lo cual se los dejo de tarea).

Ya tenemos todo listo y aún seguimos sin noticias de la base de datos 🙂 . Pues bien, es hora de que hablemos un poco de ella.

Existen dos estrategias a seguir para definir la DB: la primera es crear el esquema de la base de datos con alguna herramienta, como por ejemplo SQL Management Studio. La segunda permitir que EF 4.1 la genere por nosotros!

Por supuesto que vamos a utilizar la última opción y para eso sera necesario que en el archivo de configuración web.config agreguemos una nueva cadena de conexión para nuestra futura base de datos (esta entrada deberá tener el mismo nombre que la clase DbContext que hemos creado, para nuestro ejemplo DatosContext):

1:  <connectionStrings>
2:  <add name="DatosContext"
3:  connectionString= "Data Source=|DataDirectory|Datos.sdf"
4:  providerName= "System.Data.SqlServerCe.4.0 "/>
5:  </connectionStrings>


Nota: en nuestro caso vamos a usar como proveedor SQL Server Compact Edition 4.0 pero podriamos utilizar SQL Sever o MySql con solo modificar dicho parámetro dentro de la cadena de conexión.

Ahora simplemente ejecutamos y ya podremos crear nuestras primeras entidades:

Nuestra app corriendo

Nuestra app corriendo

Entramos al alta de Agendas:

Formulario de alta

Formulario de alta

Y creamos nuestra primer entidad:

Agregando nuestra primer entidad

Agregando nuestra primer entidad

Como podemos ver, los datos se guardaron sin necesidad de tener que crear manualmente la DB. Validemos esto abriendo el explorador de soluciones:

Base de datos creada

Base de datos creada

EF para generar automaticamente nuestra base de datos buscara dentro del archivo de configuración una cadena de conexión que tenga el mismo nombre que la clase heredada de DbContext y utilizando esta información creará el archivo correspondiente:

Modelo sobre el cual EF se basa para crear la DB

Modelo sobre el cual EF se basa para crear la DB

Podremos inspeccionar la base de datos desde el explorador de servidores (para poder visualizar la DB creada con SQL Server CE 2.0 deberemos instalar previamente el Visual Studio 2010 SP1):

Estructura de la DB creada

Estructura de la DB creada

La tabla EdmMetadata contiene información acerca de la estructura de los objetos del modelo utilizados al momento de crear la base de datos.

Para finalizar, supongamos que tenemos que modificar el modelo, deberiamos redefinir nuestra DB cierto? por defecto EF4.1 al detectar una modificación en el modelo no modifica la estructura de nuestra DB, solamente el contenido de la tabla EdmMetadata.

Para solucionar esto tenemos distintas maneras de sincronizar el modelo con la base de datos: una es hacerlo de forma manual, modificando la estructura de la tabla/s afectadas. Sin embargo existe una manera mucho mas simple para el desarrollador y es por medio del método DropCreateDatabaseIfModelChanges que viene incluida en la libería de EF4.1.

Para esto debemos agregar la siguiente línea en el método Application_Start() del archivo global.asax:

1: Database.SetInitializer<DatosContext>
2:     (new DropCreateDatabaseIfModelChanges<DatosContext>());

Como bien lo dice su nombre, este mecanismo lo que hace es eliminar y volver a crear la base de datos, por lo que todos los registros previamente grabados se perderan. Sin embargo, una forma de solucionar este problema es insertar automáticamente registros cada vez que se genere la base de datos, y la forma de hacerlo es creando una nueva clase “inicializadora” (habré inventado una nueva palabra?) que herede de DropCreateDatabaseIfModelChanges<T> donde T sera DatosContext y en la cual vamos a sobre-escribir el método Seed():

1: public class DatosInitializer : 
2:              DropCreateDatabaseIfModelChanges <DatosContext >
3: {
4:     protected override void Seed(DatosContext context)
5:     {
6:         Agenda agenda = new Agenda ()
7:         {
8:             Propietario = "Sebis" ,
9:             FechaCreacion = DateTime .Now
10:         };
11:
12:         context.Agendas.Add(agenda);
13:     }
14: }


Ahora solo resta modificar la línea que hemos escrito anteriormente dentro de global.asax para que cada vez que se vuelva a generar la base de datos, se inserten dichos registros:

1: Database.SetInitializer(new DatosInitializer ());


Resumiendo, EF 4.1 CF me parece muy recomendable para utilizar en desarrollos de pequeña escala, y ademas facilita  enormemente ciertas tareas al desarrollador, como por ejemplo evitar muchas de las configuraciones que siempre molestan a la hora de ponerse a programar.

En la proxima entrada vamos a ver como podemos integrar los validadores de ASP.NET MVC (Data Anottations) con EF4.1.

Espero que les sea de utilidad!

Anuncios

26 comentarios en “Introducción Entity Framework 4.1 Code Firts

  1. Muy bueno Sebis, me gusto tu post, te hago una consulta, has tenido la posibilidad de implementar con algun otro ORM como NHibernate, me gustaria saber tus comentarios al respecto y si tienes algun ejemplo.

    • Hola Moisés, me alegra que te haya gustado el post. Te cuento que he trabajado con otros ORM como LinqToSql pero desde hace un tiempo dejamos de utilizarlo luego de que Microsoft anuncio que iba a dejar de darle soporte.

      Otro ORM que utilice es NHibernate – https://sebys.com.ar/2010/12/12/nhibernate-en-net/ – del cual me llevo buenos recuerdos, salvo por el tema de las configuraciones 🙂 (no se en cuanto se mejoro este tema con las versiones mas recientes) … y por último en los proyectos más recientes estamos empezando a utilizar esta nueva versión de EF, que a gusto personal es con la que me siento más cómodo trabajando.

      Abrazos.

  2. Hola, vengo del mundo php y estoy empezando con asp mvc, he leído este articulo que me pareció muy interesante, lo que no puedo darme cuenta es si para hacer la conexión a la base de datos se solicitan usuario y contraseña tal como hace mysql con php… y si se solicitan, estas dónde van?
    saludos

    • Hola Daniel. En el ejemplo del post no utilice un usuario y contraseña para conectarme a la Base de Datos ya que utilice SqlCE 4.0 (la cual no trabaja bajo ese esquema, si podemos especificarle un password pero no un usuario). De todas formas, si quisiera especificarle una contraseña, lo haría en la cadena de conexión – connectionstring – dentro del archivo web.config.

      En el caso de que utilizaras una DB bajo SQL Server o MySQL las credenciales (usuario y contraseña) las especificarías en dicho archivo.

      Para conocer mas sobre como definir las cadenas de conexiones en los diferentes motores de base de datos te recomiendo el siguiente enlace: http://www.connectionstrings.com/.

      Abrazos!

  3. Hola Sebis, de vuelta por estos lados, vos sabes que estoy tratando de hacer un ejemplo con imagenes, esto seria como el siguiente ejemplo:

    public class Img
    {
    public int ImgId {get; set; }
    public Image Imagen {get: set;}
    }

    Como vez la idea es guardar imagenes en una DB, te consulto ara ver si has realizado algun ejemplo sobre este tema o si me podes pasar algun ejemplo que hubieras visto por ahí, bueno desde ya gracias y saludos.

  4. Hola Sebis, la verdad que estuve bastante, pero al fin me resulto, ahi ya lo hice, ahora estoy haciendo pruebas, despues hago un POST sobre esto y te lo comparto.

    Te cuento el proceso, a partir de una clase que guarde en base de datos un valor en Byte[] tuve que crear un metodo que sube la imagen al server, despues la convierte a byte[] y despues guarda esos bytes, ahora estoy haciendo el resto que es que pueda mostrar la imagen en todas las vistas.

    Bueno te repito que me fue muy util los ejemplos que me pasaste, un abrazo Sebis.

  5. Hola Sebis, estuve leyendo tus post. Te felicito por lo bien explicados que están y lo útiles que son. Estoy por empezar un desarrollo un tanto grande y aún estoy tratando de definir la arquitectura a utilizar. No estoy seguro de usar MVC o WebForms y tampoco se si usar EF o NHibernate. Me gustaría que me des una opinión al respecto. Al margen de eso mi consulta puntual es como funciona el CF en un entorno de producción. Es decir, supongamos que desarrollo la aplicación utilizando esta técnica. La pongo en producción y luego necesito agregar un campo. Eso va a hacer que todo mi base de datos se regenere? Muchas Gracias. Saludos

    • Hola Leandro, antes que nada me alegra que te haya gustado el blog. Paso a responderte tus dudas.

      Primer punto: para el tipo de proyectos que estas por encarar te recomiendo que utilices ASP.MVC (preferentemente la última versión: 3, ya que trae muchísimas features que facilitan las tareas del desarrollador, encontraras en mis post menciones sobre esto). En cuanto a EF o NHibernate, la verdad que son dos ORM muy potentes, personalmente me inclino por EF ya que en mi experiencia no tuve que lidiar con tantas configuraciones como en NH (aunque desconozco si en la ultima versión de NH para .NET el tema de las config y XML sigue siendo tan tedioso).

      Segundo punto: esta pregunta fue una de las primeras que me hice al ver como funcionaba EF CF. Por lo que me puse manos a la obra y publique un sitio siguiendo desarrollado con esta técnica. Lo siguiente fue modificar el modelo en mi entorno de desarrollo y volver a generar la base de datos a partir de mi nuevo modelo. Publique nuevamente el sitio y por supuesto “exploto” 🙂 . Para solucionar esto tuve que: 1 – Modificar manualmente la DB de producción (agregando, quitando, modificando… las tablas o columnas que fueron afectadas). 2 – Actualizar el valor Hash de la tabla EdmMetadata ya que contiene el nuevo esquema. Realizado esos dos cambios volvió a levantar el sitio corriendo por detrás el nuevo modelo.

      Espero que te sea de utilidad y cualquier duda seguimos en contacto.

      Abrazos!

  6. ¿Cómo hago para añadir características más avanzadas en el modelo Code First? Como por ejemplo, contraseña para la BD, Enumeraciones y limitación de caracteres para los tipos string (varchar(30)).

  7. Hola Sebis,
    Ante que nada felicitaciones por tu excelente trabajo. Me quede colgado con la pregunta de Leandro en cuanto a lograr que no se borren los datos de la base al modificar el modelo.

    Tengo un sitio en producción ya hace meses y con datos cargados al cual tengo que realizar modificaciones. Mi pregunta es como hago para que no se borren los datos que ya existen en la base actual?? No entiendo muy bien a que te referis y como hacer la modificación en EdmMetadata. Que es lo que tengo que cambiar??

    Muchas gracias por tu tiempo y felicitaciones nuevamente.

  8. creo que es un acercamiento bueno a las soluciones ORM pero no creo que supere a NHibernate, si bien tiene algunas cosas complejas, esta muy optimizado, es maduro y mejora muchisimo el rendimiento cuando se lo utiliza con un sistema de cacheo de segundo nivel como SysCache. Me gusto mucho este post.

    • Coincido con vos Silvio. Si bien EF ha mejorado con cada lanzamiento, creo que no ha madurado lo suficiente como para estar a la altura de NH. De todas formas, puede ser una excelente opción para ciertos tipos de proyectos.

      Abrazos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s