martes, 5 de julio de 2011

Entity Framework: Code First

Finalizando la serie de posts sobre los enfoques de Entity Framework, ahora intentaré explicar el enfoque Code First.

Puedes leer mis posts anteriores sobre Database First y Model First.

Este post es más bien conceptual, puede contener algunos detalles prácticos, pero no pretende mostrar ejemplos ni guías paso a paso. En futuros post intentaré dar ejemplos prácticos sobre cada uno de estos enfoques.

Code First

Este enfoque está disponible a partir de la versión ADO.NET Entity Framework 4.1 y nos permite crear un modelo de clases POCO (Plain Old CLR Object) a partir del cual podemos generar una base de datos y/o mapear esas clases a una base de datos existente.

Aquí no existe un archivo edmx con las definiciones XML del modelo conceptual, el modelo de datos y el mapeo entre ambos.

El modelo conceptual está definido por el conjunto de clases que hemos creado para representar a las entidades de nuestro modelo de dominio. La idea es que nuestras clases POCO sean mapeadas directamente a la base de datos.

La ventaja de usar clases POCO es que el modelo de clases es más limpio y las clases no tienen dependencia con EntityFramework (como sucede cuando las entidades heredan de EntityObject, implementan ciertas interfaces y contienen atributos).

 

¿Cómo se mapean las clases POCO a la base de datos?

De forma predeterminada, se utiliza un mapeo por convención en lugar de configuración. Es decir, si no especificamos el mapeo, se utilizan los nombres de las clases y sus propiedades para generar los nombres de las tablas y sus campos.

Este mapeo por convención puede ser suficiente en nuevos proyectos, donde estamos definiendo y diseñando el modelo conceptual y la base de datos desde cero.

 

¿Qué pasa si ya tengo una base de datos heredada?

Si el esquema de la base de datos heredada coincide con el modelo conceptual, entonces el mapeo por convención seguirá siendo suficiente y aplicable y todos felices! (Probabilidad: 0.0000001%)

La experiencia indica que si ya tenemos una base de datos heredada, es altamente probable que haya diferencias con el modelo conceptual utilizado en la aplicación. Entonces:

  • ¿Qué hacemos cuando el esquema de base de datos es diferente al modelo conceptual?
  • ¿Qué tal si quiero especificar restricciones, tipos de datos o validaciones a los campos?

Bien, podemos resolver estas cuestiones y otras tantas a través de:

  1. Data Annotations
  2. Mapping Fluent API

 

Data Annotations

Estas clases están disponibles en el namespace System.ComponentModel.DataAnnotations y permiten especificar restricciones o validaciones, especificar nombres de tablas o campos, etc.

image_thumb11

Hay dos artículos interesantes sobre Data Annotations que recomiendo (en inglés):

 

Mapping Fluent API

La segunda alternativa que Code First ofrece para definir el mapeo entre el modelo conceptual y la base de datos es mediante Fluent API. Esta API permite especificar la configuración de mapeo y otras configuraciones mediante código.

image_thumb3

Los siguientes enlaces contienen un artículo interesante con ejemplos sobre Code First Fluent API y un video paso a paso:

 

¿Y el contexto de datos de Code First?

De forma predeterminada, con el enfoque Database First y Model First disponemos de una clase ObjectContext del cual hereda el contexto de datos de nuestra aplicación.

Con el enfoque Code First tenemos un nuevo contexto llamado DbContext del cual debe heredar el contexto de datos de nuestra aplicación.

image_thumb5

En el contexto de datos, básicamente estamos definiendo cuáles son los conjuntos de entidades que serán mapeados a la base de datos.

Adicionalmente, podemos usar inicializadores de bases de datos, especificar configuraciones de mapeo o interceptar las operaciones de SaveChanges (entre otras).

DbContext no es más que una versión simplificada de ObjectContext, y también puede ser usando con los enfoques Database First y Model First.

 

¿Cómo o cuando se genera la base de datos?

Cuando se crea una instancia de DbContext, de forma predeterminada, se utiliza una estrategia de inicialización que crea a base de datos si no existe, opcionalmente se puede agregar código para insertar registros después de la creación.

Estas operaciones de inicialización pueden ser implementadas usando el método Database.SetInitializer. Éste método toma como parámetro una estrategia de inicialización de base de datos.

Entity Framework Code First incluye 3 inicializadores:

  1. CreateDatabaseIfNotExist
  2. DropCreateDatabaseAlways
  3. DropCreateDatabaseIfModelChanges

Podemos utilizar estos inicializadores de base de datos, cuando la aplicación se inicia. Por ejemplo, en una aplicación web podríamos usarlo en el evento Application_Start del archivo global.asax, en una aplicación de consola podríamos incluirlo en el método Main del programa principal.

image

Adicionalmente, podemos crear una clase que hereda de alguno de estos inicializadores y sobreescribir el método Seed para insertar registros después que la base de datos es creada.

image

Luego, usamos esta clase al iniciar la aplicación:

image

 

¿Cómo sería la inicialización de base de datos en un entorno de producción?

Bueno, es claro que en el entorno de desarrollo o pruebas, la inicialización de base de datos puede ser muy útil. Pero en un entorno de producción podría ser un problema.

Simplemente podemos “apagar” la inicialización de base de datos, pasando null como parámetro del método SetInitializer:

image

 

Conclusión

  • Code First es el nuevo enfoque soportado por Entity Framework. Permite mapear nuestras clases POCO directamente a la base de datos.
  • De forma predeterminada, el mapeo es por convención en lugar de configuración.
  • Configuración adicional de mapeo puede especificarse mediante Data Annotations o Fluent API.
  • DbContext API nos permite realizar las operaciones de acceso a datos.

Espero que esta serie de posts haya aclarado un poco más sobre las alternativas de trabajo con Entity Framework.

Dedicaré nuevos posts con ejemplos más prácticos de cada uno de estos enfoques, ventajas, desventajas, limitaciones, etc.

Saludos
~Gus

5 comentarios:

Anónimo dijo...

hola he buscado por la web y no he podido encontrar como puedo cambiar la conexión a la base de datos en tiempo de ejecución , alguna idea.

saludos.

.NET en latino dijo...

Usando EF podés pasar una cadena de conexión en el constructor del contexto.

var db = new BookstoreContext(connString)

Poncho dijo...

Gustavo, excelente serie de artículos, no conocia la integración de Fluent Interface dentro de .NET, saludos!

Anónimo dijo...

Como puedo generar un diagrama de clases con este metodo de code first??? Gracias

.NET en latino dijo...

Supongo que lo que buscás es usar clases POCO con un diagrama de Entity Framework (EDMX). El enfoque Code First implica que tu eres responsable de escribir las clases de tu modelo (Entidades) y también de escribir el mapeo de esas clases a tu BD (usando Fluent API o Data Annotations). Con este enfoque no hay diagramas ni generación de código. No hay EDMX en Code First.

Puedes agregar Diagramas de clases estándar a tu proyecto, pero no son diagramas de Entity Framework.

Si lo que buscas es tener las entidades y el mapeo expresado en un EDMX pero al mismo tiempo generar entidades POCO, puedes usar una extensión llamada 'Entity Framework POCO Generator'. Esta extensión permite generar clases POCO basadas en plantillas T4 y mantener el EDMX. Las clases generadas son más "limpias" (POCO) y el contexto de datos que usa es DbContext.

Googlea acerca de EF POCO Generator y encontraras varios POSTs y tutoriales.

Finalmente, considera que esto no es Code First, simplemente estarás usando entidades más limpias y livianas junto al EDMX.

Espero haya aclarado el tema.
Saludos, Gustavo