Traducción aproximada del artículo Using EF “Code First” with an Existing Database publicado en inglés por Scott Guthrie el 3 de agosto del 2010.

 

El mes pasado discutí la nueva opción para EF llamada código primero. Este nuevo componente permite un eficiente flujo de desarrollo centrado en código. Nos permite:

  • Trabajar con datos sin nunca tener que abrir un diseñador o lidiar con correspondencias en XML
  • Definir objetos del modelo usando simples clases tradicionales sin tener que derivar de clases base específicas
  • Usar la modalidad de convención en vez de configuración para el almacenaje de datos, evitándonos tener que configurarlo

En el artículo original introduje el concepto de código primero de EF y demostré como usar las reglas que incluye para la creación de bases de datos. Estas convenciones predeterminadas funcionan muy bien con aplicaciones nuevas y nos liberan de toda configuración a la hora de establecer relaciones ente las clases y la base de datos. Posteriormente expliqué, en un segundo artículo, cómo se pueden redefinir las reglas para crear correspondencias personalizadas y así alterar la creación del esquema de datos.

Hoy voy a responder a una pregunta que han hecho varios: “¿cómo puedo usar el código primero de EF cuando ya tengo una base de datos?”

 

Usando código primero con una base de datos existente

La biblioteca de código primero de EF trabaja muy bien con bases de datos ya existentes, permitiendo que podamos usar un tipo de desarrollo centrado en código. Específicamente, nos deja usar clases simples y tradicionales (conocidas como clases POCO) para el modelo de la aplicación, y crear correspondencias a la base de datos ya sea mediante convenciones predeterminadas, o configurando nuestras propias reglas para la creación del esquema de datos.

A continuación presento instrucciones paso a paso sobre cómo usar el código primero de EF con una base de datos ya existente.

 

Paso 1: crear un proyecto de aplicación web ASP.NET

Comencemos creando un proyecto para una aplicación de web con ASP.NET. En mis dos artículos anteriores sobre código primero en EF usé ASP.NET MVC, pero esta vez voy a usar Web Forms. Recuerden que los principios con respecto a EF son los mismos para ambos tipos de aplicación en ASP.NET.

Para crear la nueva aplicación seleccionamos Archivo->Nuevo->Proyecto y escogemos la plantilla Aplicación web ASP.NET en Visual Studio 2010 (o la versión gratuita Visual Web Developer 2010 Express).

La plantilla de proyectos “Aplicación web ASP.NET” es atractiva como base para aplicaciones nuevas por proveer un arreglo de página maestra con diseño basado en CSS (describí esta plantilla en un artículo anterior). El proyecto creado viene con varios archivos:

 

Proyecto generado con la plantilla de aplicación web de ASP.NET.

 

En realidad no necesitamos esos archivos en nuestro ejemplo (podríamos haber usado la plantilla Aplicación web vacía de ASP.NET), pero ayudan a que la aplicación se vea un poco mejor desde un principio, así que los vamos a usar.

 

Paso 2: agregar una referencia al ensamblaje código primero de EF

El siguiente paso es añadir al proyecto una referencia a la biblioteca de código primero de EF mediante hacer clic derecho en el nodo References del proyecto y seleccionar Agregar referencia.

Al referencia a agregar se halla en \Archivos de programa\Microsoft ADO.NET Entity Framework Feature CTP4\Binaries (o en el GAC si usaron la versión RC1) donde fue colocado por el instalador. Después de eso la referencia parece en el nodo References:

 

El proyecto requiere el ensamblaje System.Data.Entity.

 

Paso 3: base de datos Northwind

Si ya tienen la base de datos Northwind (u otra que deseen usar) en su servidor SQL pueden saltar este paso.

Si todavía no tiene Northwind instalada, la pueden obtener acá. Pueden usar los archivos .SQL incluidos o copiar el archivo Northwnd.mdf al la carpeta App_Data de la aplicación:

 

El proyecto usa la base de datos Northwind.

 

Paso 4: crear la capa del modelo

Ahora vamos a crear las clases del modelo y usar la biblioteca código primero de EF para asociarlas a la base de datos Northwind. El código necesario es el siguiente, no se ocupa nada más:

 

public class Product
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public decimal? UnitPrice { get; set; }
    public bool Discounted { get; set; }

    public virtual Category Category { get; set; }
}

 

public class Category
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string Description { get; set; }
    public byte[] Picture { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

 

public class Northwind : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

 

Estos son algunos detalles sobre el código y su funcionamiento:

 

Clases POCO para el modelo

La biblioteca de código primero de EF nos permite usar objetos simples y llanos del CLR (o POCO) para representar las entidades en la base de datos. Por lo tanto, no necesitamos usar clases base especiales ni implementar una interfase específica o agregar atributos de ningún tipo. De esta manera nuestras clases se mantienen en ignorancia de su mecanismo de almacenaje.

En el ejemplo arriba, las clases Product y Category son POCO que usaremos para representar las tablas Products y Categories en la base de datos Northwind. Las propiedades de las clases corresponden a las columnas de las respectivas tablas mientras que cada instancia es una fila de la tabla.

 

Columnas con valores nulos

Noten que algunas de las propiedades en la clase Product admiten valores nulos (la declaración Decimal? indica que puede tener valor nulo). Si la columna en la base de datos admite valores nulos, entonces la propiedad correspondiente en la clase también debe aceptarlos:

 

public class Product
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public decimal? UnitPrice { get; set; }
    public bool Discounted { get; set; }
    public int CategoryID { get; set; }

    public virtual Category Category { get; set; }
}

 

La línea 7 no aparece en el listado del artículo original. Debido a un cambio en las convenciones de generación del esquema de datos en el CTP5, ahora hay que incluir una referencia a la clave externa. Para más información pueden ver el artículo de Scott sobre el CTP5.

 

Es posible también omitir del modelo columnas que admiten valores nulos si no son necesarias. Por ejemplo, la tabla Products en Northwind tiene una columna llamada QuantityPerUnit y otra UnitsOnOrder, ambas permitiendo valores nulos. La clase Product no tiene propiedades para representarlas, pero como pueden recibir valores nulos, es posible todavía hacer consultas, modificar, insertar, y borrar productos sin ningún problema.

 

Propiedades de asociación y cargado diferido

El código primero de EF facilita el uso de relaciones de claves primarias y externas en la base de datos y expone propiedades en las clases del modelo que nos ayudan a navegar las clases usando esas relaciones.

En el código arriba, la clase Product expone la propiedad Category, y la clase Category expone Products. Estas propiedades permiten el uso de relaciones de clave primaria y externa entre las dos tablas para obtener instancias del modelo. Con todo y todo, las propiedades siguen siendo de tipo POCO sin requerir un tipo especial de colección en su definición.

Las propiedades de asociación marcadas como virtuales son, por defecto, cargadas de modo diferido. Es decir, si uno obtiene una entidad Product, la información sobre la categoría no es cargada hasta que sea leída la propiedad Category (a menos que uno cargue la propiedad explícitamente en la consulta LINQ).

 

Clase de contexto de EF

Luego de crear las clases Product y Category, usamos el componente de código primero de EF para crear una clase que sirve como contexto de datos y que crea la asociación entre nuestros modelos de clases POCO y la base de datos:

 

public class Northwind : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

 

La clase Northwind es el medio usado para asociar las clases Product y Category con la base de datos. Deriva de la clase DbContext provista por la biblioteca de código primero de EF y expone dos propiedades que corresponden a tablas en la base de datos. En este ejemplo estamos aprovechando las reglas predeterminadas de convención en vez de configuración para crearlas correspondencias entre tablas y clases.

Alternativamente pudimos haber redefinido el método OnModelCreating para especificar reglas personalizadas en caso de que nuestras clases necesiten diferir del esquema de datos. Mi artículo anterior sobre código primero cubre este tema.

 

Paso 5: Configurar la cadena de conexión

Ya hemos escrito todo el código necesario para definir la capa del modelo. Nuestro último paso, ante de poder usarlo, es configurar una cadena de conexión para la base de datos.

En el artículo original mencioné una opción en la biblioteca de código primero de EF que automáticamente regenera la base de datos. Esta opción es especialmente útil en casos de desarrollo de aplicaciones nuevas, ya que nos permite concentrarnos en el diseño de la capa del modelo sin tener que gastar tiempo en actualizar el esquema en la base de datos con cada cambio.

No obstante, es importante recordar que se trata de una opción, y no es requerida en lo absoluto. Si la cadena de conexión apunta a una base de datos ya existente, EF no intentará crearla de nuevo de forma automática. La opción de regeneración automática sólo puede ser activada de forma explícita, por lo que no hay razón para preocuparse de que vaya a borrar y recrear una base de datos ya existente.

En nuestro caso específico, no queremos que la base de datos sea regenerada, de manera que vamos a configurar la cadena de conexión a la base de datos de Northwind que ya tenemos. Esto se hace en el archivo web.config:

 

<connectionStrings>
  <add name="Northwind"
       connectionString="data source=.\SQLEXPRESS;
                 Integrated Security=SSPI;
                 AttachDBFilename=|DataDirectory|\Northwnd.mdf;
                 User Instance=true"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

 

El componente de código primero de EF se adhiere a la convención de que las clases del contexto de datos tienen el mismo nombre que las cadenas de conexión. Por llamarse Northwind, nuestra clase buscará una cadena de conexión con el nombre Northwind. La cadena en sí configura in conexión a una base de datos local en SQL Express. También sería posible que señale a un servidor SQL remoto.

 

Paso 6: usando las clases del modelo

Escribamos ahora una (muy) sencilla página que use las clases del modelo Northwind y despliegue información tomada de la base de datos.

Vamos a empezar añadiendo una nueva página haciendo clic derecho en proyecto y seleccionando Agregar->Nuevo elemento y luego escogiendo Formulario Web Forms que usa una página maestra. De nombre le ponemos Products.aspx y su página maestra es Site.master, que fue creada por la plantilla del proyecto.

En la página insertamos un control <asp:GridView> y lo configuramos para que muestre el nombre y precio de los productos:

 

<asp:GridView ID="GridView1"
                AutoGenerateColumns="false"
                GridLines="none"
                runat="server">
    <Columns>
        <asp:BoundField DataField="ProductName"
                        HeaderText="Name" />
        <asp:BoundField DataField="UnitPrice"
                        DataFormatString="{0:C2}"
                        HeaderText="Price" />
    </Columns>
</asp:GridView>

 

En el archivo de código subyacente podemos escribir la siguiente consulta en LINQ usando el modelo para obtener todos los productos activos de la base de datos y atar el resultado al control GridView (MD: el código incluye una ligera, pero importante, corrección en la línea 9.):

 

protected void Page_Load(object sender, EventArgs e)
{
    Northwind northwind = new Northwind();

    var products = from product in northwind.Products
                   where product.Discounted == false
                   select product;

    GridView1.DataSource = products.ToList();
    GridView1.DataBind();
}

 

Es posible ahora ejecutar la aplicación y navegar a la página Products.aspx para obtener un listado de los productos:

 

Listado de productos producido al adaptar el código primero a una base de datos existente.

 

Terminando con una aplicación de ejemplo que muestra cómo usar código primero con una base de datos existente.

 

Descargando el ejemplo

Pueden descargar aquí la versión completa del ejemplo. Supongo que ya han instalado la versión más reciente del componente de código primero de EF4 y SQL Server Express.

 

Ejemplos adicionales

Los siguientes son ejemplos adicionales de código demostrando el uso de Northwind en casos comunes.

 

Consultas a través de relaciones

La expresión LINQ abajo muestra cómo obtener objetos de tipo Product basándonos en la categoría a la que pertenecen. Noten cómo es posible crear consultar en LINQ que abarcan tanto Product, como el objeto Category asociado mediante la propiedad con el mismo nombre. El filtrado se ejecuta en el servidor por lo que sólo los Productos son devueltos a la capa del modelo (haciéndolo más eficiente);

 

Northwind northwind = new Northwind();

var products = from product in northwind.Products
               where product.Category.CategoryName == "Beverages"
               select product;

 

Usando el método Find para obtener un solo producto

Además de poder escribir expresiones LINQ, el componente de código primero de EF provee el método Find() en colecciones de tipo DbSet<T>, permitiéndonos escribir código como el siguiente par obtener una instancia única basándonos en el ID:

 

Northwind northwind = new Northwind();

var products = northwind.Products.Find(4);

 

Insertando una categoría nueva

El siguiente código muestra cómo añadir una categoría a la base de datos:

 

Northwind northwind = new Northwind();

Category category = new Category();
category.CategoryName = "Ejemplos de Scott";
category.Description = "Otro ejemplo.";

northwind.Categories.Add(category);
northwind.SaveChanges();

 

Noten que creamos un objeto de tipo Category, asignamos valores a sus propiedades y lo agregamos a la colección de categorías del contexto. Al final entonces usamos SaveChanges() para almacenar los cambios en la base de datos.

 

Insertando (y asociando) un nuevo producto y categoría

El siguiente ejemplo muestra cómo crear una Categoría y un Producto, hacer que el producto pertenezca a la categoría y luego enviar ambos a la base de datos:

 

Northwind northwind = new Northwind();

Category category = new Category();
category.CategoryName = "Ejemplos de Scott";
category.Description = "Y otro ejemplo más.";

Product product = new Product();
product.ProductName = "Mi producto";
product.Category = category;
product.UnitPrice = 9.99M;

northwind.Products.Add(product);
northwind.Categories.Add(category);
northwind.SaveChanges();

 

La parte clave es cuando, en la línea 9, se crea la asociación entre la categoría y el producto usando la propiedad Catrogory del producto. No es necesario asignar de forma explícita un valor a la propiedad CategoryID, ya que es actualizado automáticamente al mandar los cambios a la base de datos.

EF usa un patrón llamado unidad de trabajo (tal vez traducible como tarea discreta) implicando que lleva cuenta de los cambios hechos al contexto y, cuando se invoca SaveChanges(), los envía todos a la base de datos en una sola transacción (es decir, o todos los cambios se llevan a cabo, o ninguno). Esto hace más fácil garantizar que la base de datos no quede en estado inconsistente, con algunos cambios aplicados y otros no.

En el ejemplo citado, tanto el producto como la categoría son creados en la base de datos, o ninguno si hay un error (también lanzando una excepción).

 

Actualizar un producto y guardar los cambios

El código siguiente muestra la forma en que se puede obtener un producto de la base de datos para luego actualizarlo y guardarlo de vuelta. Más arriba demostré cómo usar el método Find() para encontrar un producto basado en su ProductID. Abajo usamos una expresión LINQ para encontrarlo ahora basándonos en su nombre:

 

Northwind northwind = new Northwind();

var product = northwind.Products.Single(
                                 p => p.ProductName == "Chai");
product.UnitPrice = 2.33M;

northwind.SaveChanges();

 

Es posible hacer muchos otros tipos de cambios (a objetos existentes o añadiendo nuevos). Al invocar SaveChanges() los cambios son enviados a la base de datos en una sola transacción.

 

Convenciones preconfiguradas vs. reglas personalizadas de correspondencia

Cuando creamos la clases Product y Category, usamos las convenciones preconfiguradas en el código primero de EF parta crear correspondencias con la base de datos. Evitando así tener que especificar reglas personalizadas y manteniendo el código conciso.

No obstante, habrá veces en que el esquema de datos no nos parece adecuado, queriendo hacer un modelo de datos diferente en el código. En ese caso pueden usar mi artículo sobre el uso de correspondencias personalizadas para ver ejemplos sobre cómo especificar tales reglas. Su uso es el mismo cuando necesitamos adaptarnos a bases de datos ya existentes.

 

Conclusión

Estoy muy entusiasmado con el nuevo componente de código primero de EF y creo que provee una excelente forma de trabajar puramente con código en el manejo de datos. Permite incrementar la productividad y es muy flexible. En especial me gusta porque ayuda a crear código despejado, conciso y fácil de mantener. Espero que estos tres artículos les permitan obtener una vista general de las posibilidades que abre tanto para bases de datos nuevas como las ya existentes.

Pueden obtener acá el CTP 4 de la biblioteca de código primero de EF (o el RC1 aquí). Para obtener aún más información sobre código primero en EF asegúrense de consultar estos artículos por el equipo de ADO.NET:

Espero haberles sido de ayuda,

 

Scott

 

2 Respuestas a “Usando Código Primero de EF con una base de datos ya existente”

  1. Invitado dice:

    entonces se pone o no el campo categoryID???? no esta bien explicado, creo yo

Responder



Licencia de uso

El contenido de las traducciones está sujeto a los términos de protección de derechos de uso de los autores originales quienes han autorizado su publicación en este blog. Asegúrese de entender los terminos de la licencia de cada autor antes de usar tal contenido.

Mis propios artículos son publicados bajo los términos de la Licencia Reconocimiento-Compartir bajo la misma licencia 3.0 Estados Unidos de Creative Commons:

Creative Commons License
Blog de Maromas Digitales by Maromas Digitales, LLC is licensed under a Creative Commons Reconocimiento-Compartir bajo la misma licencia 3.0 Estados Unidos License.

License

The contents of all translated articles is subject to the copyright and licensing terms of the original authors and has been published here with their express permission. Verify the original author's licensing terms before using the contents of these articles.

My own articles are licensed under the Creative Commons Attribution-Share Alike 3.0 United States License:

Creative Commons License
Blog de Maromas Digitales by Maromas Digitales, LLC is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.