Entity Framework Code-First

Hola a todos,

Hoy vamos a hablar de una de las formas que tenemos para crear una base de datos para nuestro proyecto. Concretamente de Entity Framework Code-First.

Antes de hablar de EF Code-First vamos a recordar brevemente cual es la manera común de crear una base de datos usando Entity Framework:

Si queríamos hacer uso de bases de datos en nuestra aplicación, lo más común era crear una base de datos (Usando Sql Server normal, express o compact edition), crear sus tablas y añadir algúna que otra fila para probar nuestra base de datos.

Una vez teníamos nuestra base de datos lista, creabamos un ASP.NET Entity Data Model que haría de intemerdiario entre nuestra aplicación y la base de datos. Dicho .edmx (Entity Data Model) GENERABA clases por cada tabla de nuestra base de datos.

Por ejemplo, si teníamos una clase Persona y una clase Trabajo, el Entity Data Model generaría una clase llamada Personas y otra llamada Trabajos que serían como ya he dicho, la representación de las tablas de la base de datos en clases C#.

La idea es buena, muy buena. El problema es que las clases que se generan, pueden contener mucha redundancia y por normal general no son nada limpias (Luego veremos un ejemplo).

Entonces… ¿Hay alguna otra manera? Por supuesto. Aquí es donde entra:

Entity Framework Code-First

Como su nombre indica (El código primero), nos incita a escribir primero las clases que representan las tablas y luego crear dichas tablas.

En otras palabras, crearemos una clase por cada tabla de la base de datos, y luego generaremos dichas tablas automáticamente (sin redundancias ni nada).

Para este ejemplo vamos a usar ASP.NET MVC 3 y Sql Server Compact Edition 4. En caso de que no lo tengás instalado, podéis usarlo en cualquier otro tipo de aplicación, WPF, ASP.NET 4… La idea y el conocimiento adquirido vale para cualquier otro tipo de proyecto.

Aún así, recomiendo usar SQLServerCE 4 a todos aquellos que necesiten bases de datos pequeñitas y embebidas y así no tirar de mastodontes como Sql Server.

NOTA: Necesitas del Service Pack 1 de VS2010 instalado para poder hacer uso de SQLServerCE 4 (A dia de hoy es beta, pero perfectamente usable)

Pensando que tenéis instalado Asp.NET MVC 3, SQl Server CE 4 (tanto toolkit como el runtime) y VS2010 SP1 Beta pues vamos allá:

Iniciamos un nuevo proyecto ASP.NET MVC 3, lo llamaremos: TutorialEFCodeFirst. Le decimos que queremos una aplicación de internet para no tener que marearnos con cosas irrelevantes para este artículo.

Una vez tengamos nuestro proyecto creado, necesitamos añadir Entity Framework a nuestro proyecto, para ello lo mejor sería usar NuGet para facilitarnos la vida.

Abrimos la consola de NuGet yendo al menú View->Other Windows->Package Manager Console. Una vez en la consola simplemente tenemos que teclear:

Install-package EFCodeFirst

Con esto ya tendremos la librería cargada en nuestro proyecto.

Ahora vamos con la base de datos… ¿Qué vamos a representar? Qué tal si seguimos con el ejemplo anterior de personas y trabajos? Pues vamos a ello:

Click derecho en Models, añadir nueva clase, la cual llamaremos Persona:

public class Persona
{
	public int ID { get; set; }
	public int TrabajoID { get; set; }
	public string Nombre { get; set; }
	public int Edad { get; set; }

	public virtual Trabajo Trabajo { get; set; }
}

Añadiremos también una clase llamada Trabajo:

public class Trabajo
{
	public int ID { get; set; }
	public string Nombre { get; set; }
	public string Descripcion { get; set; }

	public virtual ICollection<Persona> Personas { get; set; }
}

Como véis, no dejan de ser clases normales. No tienen nada fuera de lo común y no heredan de ningún tipo de clase o interfaz. Lo interesante es:

La relación entre la clase Trabajo y Persona es 1:N. Eso quiere decir que un trabajo puede hacerlo varias personas y una persona tiene un trabajo. La teoría de base de datos nos dice que en estos casos, la clave de la tabla que tiene el 1 se propaga a la clase N. En este caso, en la clase/tabla Persona tendremos una referencia al ID de Trabajo.

A parte de esto, cada clase ha de tener digamos un “enlace” con cada clase que se relaciona. En este caso:

Persona se relaciona con Trabajo y como Persona solo se relaciona con una instancia de Trabajo pues guardamos una simple instancia.
En el otro caso, como Trabajo se relaciona con muchas Personas pues guardará una colección de estas.
Vale, ya tenemos las clases que serán las tablas de la base de datos, pero todavía necesitamos la última pieza que hará que todo esto funcione.

Si habéis generado las clases a partir de la base de datos como comenté al principio del artículo, veréis que además de las clases, genera una clase llamada Contexto la cual nos hace de intermediario entre la base de datos y nuestro código.

En nuestro caso, necesitamos escribir esa clase manualmente, pero claro, queda mucho más simple que su homóloga. Por simplicidad, crearemos este contexto en la carpeta Models:

public class TutorialContext : DbContext
{
	public DbSet<Persona> Personas { get; set; }
	public DbSet<Trabajo> Trabajos { get; set; }
}

Como véis, es una clase bastante sencillita, simplemente creamos una propiedad del tipo DbSet por cada clase que pasará a ser una tabla.

Ahora necesitamos especificar la cadena de conexión a la base de datos que se va a generar. Para el caso de SQL Server CE 4 sería así (tenemos que escribirla en el Web.config):

<connectionStrings>
	<add name="ApplicationServices"
		 connectionString="data source=.SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
		 providerName="System.Data.SqlClient" />
	<add name="TutorialContext" connectionString="Data Source=|DataDirectory|tutorial.sdf" providerName="System.Data.SqlServerCE.4.0"/>
</connectionStrings>

La cadena de conexión consta de 3 partes.

En name pondremos el nombre de la clase que hace de Contexto, en nuestro caso es TutorialContext.
En connectionString colocamos la ruta donde irá nuestra base de datos, en nuestro caso irá a la carpeta App_Data(DataDirectory).
en providerName colocamos la librería que usaremos para esto, en este caso es la libreria de SQL Server CE 4.

Ya está, no hay más. Nuestra base de datos ya está lista. Hemos creados las clases, hemos creado el contexto y finalmente hemos puesto la cadena de conexión. Nuestra base de datos se generará cuando se haga uso de ella por primera vez.

Vamos a probarla.

Por simplicidad abrimos el HomeController y ahí probaremos nuestra base de datos.

Cambiaremos el método Index por el nuestro propio:

public ActionResult Index()
{
	var db = new TutorialContext();

	var personas = from p in db.Personas
				   select p;

	return View(personas.ToList());
}

Nada fuera de lo común. El uso de nuestra base de datos es exactamente el mismo que si hubiesemos usado el otro método. Simplemente instanciamos el contexto, y como ejemplo creamos una lista de personas y la enviamos a la vista.

NOTA: Es recomendable crear un repositorio que haga de intermediario entre nuestra aplicación y la base de datos, pero para simplificar el artículo vamos a usar el contexto directamente.

Abrimos Index.cshtml y modificamos la vista acorde a nuestra aplicación:

@model IEnumerable<TutorialEFCodeFirst.Models.Persona>

@{
    ViewBag.Title = "Lista de personas";
}

<h2>Lista de personas</h2>

@foreach (var per in Model)
{
    <div>
        <h2>@per.Nombre - @per.Edad</h2>
        @if (per.Trabajo != null)
        {
            <h3>@per.Trabajo.Nombre</h3>
        }
    </div>
}

Si ejecutamos nuestra aplicación veremos que no sale ninguna persona:

Normal, no hemos añadido ninguna persona.

Ahora bien, si en el Visual Studio hacemos click en el botón para ver todos los archivos del proyecto, podemos ver que dentro de App_Data aparece nuestra base de datos.

Hacemos click derecho en la base de datos y le damos a incluir en el proyecto.

Si ahora hacemos doble click en la base de datos, podremos ver la información de esta. Podremos ver sus tablas, etc.

¿Trabajoes? A mi me ha creado la tabla con ese nombre… No pasa nada, podemos decirle al contexto qué nombre usar a la hora de crear la tabla, es tan fácil como sobreescribir un método:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
	modelBuilder.Entity<Persona>()
		.ToTable("Personas");
	modelBuilder.Entity<Trabajo>()
		.ToTable("Trabajos");
}

Simplemente a la hora de mapear las clases a tablas, elegimos el nombre.

Ahora sí:

Ya que estamos vamos a añadir algunos datos, ¿No?

Hacemos click derecho en la tabla Trabajos y le damos a que nos muestre los datos de las personas. Lo dejaremos así:

Ahora hacemos lo mismo con la tabla Personas pero usando estos datos:

Ahora que tenemos datos, simplemente tenemos que ejecutar otra vez nuestra aplicación:

Ahí están nuestros datos!!

¿Fácil verdad? Solo hemos tenido que crear las clases que serán tablas, el contexto, la cadena de conexión y finalmente introducir algunos datos de prueba.

Bueno, hasta aquí la introducción a EF Code First. Espero vuestros comentarios.

Tags: , ,

13 comentarios

  1. Excelente tutorial, vaya llevaba horas tratando de crear la conexion a la base de datos, no me habia dado cuenta que el error estaba en en Name del connectionStrings, que debia ser el mismo con que se definio en el clase contexto en el Model.
    Gracias.

  2. Precisamente por esas razones escribo estos tutoriales, porque yo me paso horas peleandome con algo y luego puedo explicarlo de forma sencilla. En concreto ese problema que has tenido lo tuve yo varias horas hasta que descubrí que el nombre debía ser el mismo que la clase, por eso lo dejé clarito jeje.

  3. Hola
    Es posible además agregar algun metodo para que llame a un procedimiento avanzado?

  4. Uhm, creo que no, creo que eso es algo propuesto para futuras versiones, si no te he entendido mal :)

  5. me lo imaginaba, porque lo mismo pasa en linq, podes armarlo vos mismo pero no podes acceder a procedimientos almacenados.
    TE HAGO OTRA CONSULTA POR FAVOR, me comentaron que el rendimiento(tiempo en obtener datos etc) que tenes accediendo a una consulta usando entity framework es casi el mismo que usando un procedimiento almacenado, es cierto esto?
    saludos

  6. Parece que es cierto, el rendimiento es casi identico, solo que los procedimientos almacenados te dan ventajas (mantenibles, usables…) tampoco te lo puedo confirmar, no he hecho tests.

  7. Buenas, excelente tutorial.
    Mi pregunta es como se haria usuando WPF en lugar de ASP.

    Muchas gracias

  8. ¿Por qué virtual? Viendo el rendimiento en cuanto a colecciones y listas, las listas consumen menos recursos y tiempo.

  9. phito, se colocan virtual para poder hacer uso de lazy loading. si le quitas el virtual se haría el query directamente.

    Todo depende de lo que busques en realidad.

    Yo por ejemplo intento serializar esos objetos en Javascript y no puedo por el lazy loading, así que para estos casos quito el virtual, pero para otras cosas se supone que te dará rendimiento.

  10. una pregunta Fox, estoy usando Visual Studio 2010 quien ya tiene instalado la caracteristica del FirstModel, pero la forma en que se declaran las clases es por una herramienta visual y cuando veo las clases creadas son exactamente iguales a que si crearan las clases desde una BD, como puedo ahcer en mi entorno para declarar la clases asi manualmente como haces tu??
    Muchas gracias por el blog

  11. No sé si entiendo tu pregunta Banzai. Simplemente hazlo como lo he descrito en este post y no uses la herramienta visual, que eso es para la otra forma de hacer las bases de datos jeje.

  12. Me gusta la forma de explicarlo, sencillo, al grano y muy claro son sofisticaciones innecesarias.

  13. ¿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)).

Dejar un comentario