Traducción aproximada del artículo Generating EF Code First model classes from an existing database publicado en inglés por Jon Galloway el 24 de febrero del 2011.

 

La biblioteca de código primero de Entity Framework permite, de forma sencilla, habilitar clases simples del CLR para que obtengan acceso a datos. Como su nombre lo indica, la idea es poder primero escribir el código y preocuparse luego por la base de datos.

Mi problema es que gusta mucho cómo trabaja el código primero de Entity Framework, y quisiera poder usarlo en proyectos y/o bases de datos ya existentes. Por ejemplo, la tienda de música MVC (MVC Music Store) ya tiene una base de datos en SQL Express prepoblada con un catálogo de música (incluyendo géneros, artistas y títulos), y aunque sería razonable en un futuro poder inicializarla con datos desde otra fuente, para la versión 3 de MVC quisimos usar la ya existente. En este caso no estoy aprovechando todas las ventajas de código primero (en especial el poder escribir código desde el que luego se genera un esquema de datos), pero aún así me beneficio de la simplicidad y brevedad de usar código solamente.

Scoot Guthrie escribió sobre cómo usar Entity Framework con una base de datos ya existente usando las convenciones de Código Primero para crear correspondencias para un esquema de datos creado con diferentes criterios. El artículo da la información necesaria para crear el modelo de clases manualmente. Sin embargo, resulta que es posible generar el modelo de clases directamente desde el esquema de datos. Ya con la esa tediosa parte hecha, se pueden modificar las clases según sea necesario. El primer paso nos salva de la larga y frustrante tarea de crear correspondencias entre los tipos de datos de SQL y .NET.

Noten que este método requiere Entity Framework 4 CTP 5 o más reciente (o, mejor aún, la versión oficial lanzada recientemente).

 

Paso 1: Generar un modelo en EF de la base de datos

El generador de código en Entity Framework necesita partir de un modelo. Es posible agregar un modelo a un proyecto y luego borrarlo, pero yo hallo más fácil crear un proyecto separado para generar las clases del modelo. Así, cuando hayamos terminado, se puede eliminar el proyecto sin afectar la aplicación, o hasta podemos dejarlo quieto en caso de que haya que actualizar el modelo de clases debido a cambios en el esquema de datos.

Para este ejemplo elegí crear una carpeta llamada Models en una aplicación nueva de MVC 3 y poner allí las clases del modelo. Haciendo clic derecho en e la carpeta, se selecciona Agregar->Nuevo elemento:

 

Agregando un nuevo elemento al proyecto. 

 

Luego se selecciona un ADO.NET Entity Data Model poniéndole el nombre que deseen.

 

Planitlla para modelos basados en ADO.NET.

 

Después hay que escoger Generar desde la base de datos. Esto es importante, pues es el fundamento para los pasos siguientes pasos donde leeremos el esquema de datos.

 

El modelo se generará a partir de una base de datos existente.

 

Aquí es donde dirigimos al asistente a la base de datos ya existente. Voy a suponer que saben cómo encontrar la ubicación de la base de datos. Si no, pueden consultar la sección de modelos y datos de la guía para el MVC Music Store donde cubro parcialmente el tema. Al seleccionar la base de datos pueden dejar sin marcar la opción de guardar la configuración de conexión en Web.Config puesto que no la vamos a necesitar para la aplicación. Luego presionen Siguiente.

 

El asistente debe ser apuntado a la base de datos de interés.

 

En esta fase hay que seleccionar los objetos de la base de datos que queremos modelar. En mi caso escogí todas las tablas e hice clic en Finalizar.

 

Escogiendo las entidades a modelar.

 

Y aquí tenemos el modelo. Si lo desean, pueden hacer cualquier modificación necesaria antes de generar el código.

 

El modelo final, basado en el esquema de datos ya existente.

 

Paso 2: agregar el generador de DbContext

Al igual que la mayoría de los generadores de código recientes en Visual Studio, Entity Framework usa plantillas T4 permitiendo así cierto grado de control sobre el proceso de generación. K Scott Allen escribió recientemente en MSDN un detallado artículo sobre el uso de plantillas T4 en Entity Famework por si desean aprender más acerca del tema. Por dicha, ya existe una plantilla que hace exactamente lo que necesitamos.

Luego de hacer clic derecho en un espacio en blanco en el diseñador de Entity Framework se selecciona “Agregar elemento de generación de código…

 

El menú de contexto en el diseñador de modelos de datos ofrece la opción de generar código.

 

De las plantillas disponibles en el grupo de Código hay que seleccionar el generador ADO.NET DbContext Generator. Si no lo ven listado entonces sería bueno cerciorarse de que tiene instalado EF 4 CTP 5 o algo más reciente y que están viendo el grupo de código. Es de notar que la plantilla de generación de DbContext es similar a la que salió el año pasado llamada EF POCO, pero con el código de parche removido (puesto que ya no es necesario).

 

Plantilla de generación de código basada en DbContext.

 

Después verán dos aterradoras advertencias de seguridad (a menos que escojan no ser avisados sobre esto de nuevo). Cada vez que recompilen el proyecto aparecen de nuevo las advertencias, por lo que yo decidí marcar la cajita impidiendo su reaparición sin que le sucediera nada malo a mi máquina (¡cruzando los dedos!).

 

Advertencia sobre el uso de plantillas de generación de código.

 

Y este es el resultado: dos plantillas (cuyos nombres terminan en .tt) han sido añadidas al proyecto y han generado el código que necesitamos.

 

Clases generadas automáticamente.

 

La plantilla “EntidadesMusicStore.Context.tt” creó una clase DbContext conteniendo las colecciones de entidades, y la plantilla “EntidadesMusicStore.tt” creó clases separadas para las tablas seleccionadas anteriormente. En el siguiente paso les vamos a añadir código adicional.

Mi recomendación es copiar de una vez los archivos .cs generados a la aplicación, ya que si por accidente se recompila el proyecto de generación, se borrará cualquier cambio que hayamos hecho.

 

Paso 3: Modificar las clases POCO para su uso

Nota: Para mis propósitos, hice numerosas modificaciones a las clases POCO luego de ser generadas. Esto no es absolutamente necesario, pero el punto importante es que se puede hacer—son nuestras clases y el componente de código primero de EF respeta ese hecho. Modifíquenlas en lo que sea necesario para la aplicación, o úsenlas tal y como son generadas.

La clase Context deriva de DbContext, quien activa el componente de código primero. La clase contiene un DbSet por cada entidad, que puede ser considerado como un tipo de List, pero con habilidades del Entity Framework.

 

//--------------------------------------------------------------
// <auto-generated>
//    Este código se generó a partir de una plantilla.
//
//    Los cambios manuales en este archivo pueden causar ...
//    Los cambios manuales en este archivo se sobrescribirán ...
// </auto-generated>
//--------------------------------------------------------------

namespace EF_CodigoPrimero.Models
{
  using System;
  using System.Data.Entity;
  using System.Data.Entity.Infrastructure;

  public partial class Entities : DbContext
  {
    public Entities()
      : base("name=Entities")
    {
    }

    protected override void OnModelCreating(
                                DbModelBuilder modelBuilder)
    {
      throw new UnintentionalCodeFirstException();
    }

    public DbSet<Album> Albums { get; set; }
    public DbSet<Artist> Artists { get; set; }
    public DbSet<Cart> Carts { get; set; }
    public DbSet<Genre> Genres { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderDetail> OrderDetails { get; set; }
  }
}

 

Tal como es generada, la clase es simple; lo que hice fue remover los comentarios, cambiar el espacio de nombres, eliminar el constructor y cambiar un poco el formato. Listo.

De haber querido podría añadir o remover DbSets, cambiar las convenciones de correspondencias de datos, y así por el estilo.

 

namespace MvcMusicStore.Models
{
  using System.Data.Entity;

  public partial class Entities : DbContext
  {
    public DbSet<Album> Albums { get; set; }
    public DbSet<Artist> Artists { get; set; }
    public DbSet<Cart> Carts { get; set; }
    public DbSet<Genre> Genres { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderDetail> OrderDetails { get; set; }
  }
}

 

A continuación examinamos las clases individuales. Algunas fueron bastante simples. Por ejemplo, en la clase Cart sólo tuve que borrar el encabezado y modificar el espacio de nombres.

 

//--------------------------------------------------------------
// <auto-generated>
//    Este código se generó a partir de una plantilla.
//
//    Los cambios manuales en este archivo pueden causar ...
//    Los cambios manuales en este archivo se sobrescribirán ...
// </auto-generated>
//--------------------------------------------------------------

namespace EF_CodigoPrimero.Models
{
  using System;
  using System.Collections.Generic;

  public partial class Cart
  {
    public int RecordId { get; set; }
    public string CartId { get; set; }
    public int AlbumId { get; set; }
    public int Count { get; set; }
    public System.DateTime DateCreated { get; set; }

    public virtual Album Album { get; set; }
  }
}

 

La clase Album requirió más cambios. Al ser generada se veía así:

 

//--------------------------------------------------------------
// <auto-generated>
//    Este código se generó a partir de una plantilla.
//
//    Los cambios manuales en este archivo pueden causar ...
//    Los cambios manuales en este archivo se sobrescribirán ...
// </auto-generated>
//--------------------------------------------------------------

namespace EF_CodigoPrimero.Models
{
  using System;
  using System.Collections.Generic;

  public partial class Album
  {
    public Album()
    {
      this.Carts = new HashSet<Cart>();
      this.OrderDetails = new HashSet<OrderDetail>();
    }

    public int AlbumId { get; set; }
    public int GenreId { get; set; }
    public int ArtistId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
    public string AlbumArtUrl { get; set; }

    public virtual Artist Artist { get; set; }
    public virtual Genre Genre { get; set; }
    public virtual ICollection<Cart> Carts { get; set; }
    public virtual ICollection<OrderDetail> OrderDetails
            { get; set; }
  }
}

 

Entonces removí el encabezado, modifiqué el espacio de nombres y eliminé algunas de las propiedades. Algo que me gusta del código primero en EF es que no hay que tener una propiedad por cada columna o clave externa del esquema de datos. Por ejemplo, podemos crear la tienda de música con código primero y comenzar con solamente algunas propiedades, añadiendo más campos y relaciones a medida que se van necesitando. Entity Framework trabaja con las columnas que le indicamos sin quejarse por las ausentes. Esta es la clase básica:

 

namespace MvcMusicStore.Models
{
  using System.Collections.Generic;

  public partial class Album
  {
    public Album()
    {
      this.OrderDetails = new HashSet<OrderDetail>();
    }

    public int AlbumId { get; set; }
    public int GenreId { get; set; }
    public int ArtistId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
    public string AlbumArtUrl { get; set; }

    public virtual Artist Artist { get; set; }
    public virtual Genre Genre { get; set; }
    public virtual ICollection<OrderDetail> OrderDetails
            { get; set; }
  }
}

 

Es mi clase, no de Entity Framework, por lo que puedo hace lo que quiera con ella. En mi caso, le agregué varias anotaciones relativas a MVC 3 para validación y estructuración, con es siguiente resultado:

 

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using System.Collections.Generic;

namespace MvcMusicStore.Models
{
  [Bind(Exclude = "AlbumId")]
  public partial class Album
  {
    public Album()
    {
      this.OrderDetails = new HashSet<OrderDetail>();
    }

    [ScaffoldColumn(false)]
    public int AlbumId { get; set; }

    [DisplayName("Género")]
    public int GenreId { get; set; }

    [DisplayName("Artista")]
    public int ArtistId { get; set; }

    [Required(ErrorMessage="El título del album es requerido")]
    [StringLength(160)]
    public string Title { get; set; }

    [Required(ErrorMessage="El precio es requerido")]
    [Range(0.01, 100.00,
     ErrorMessage="El precio debe ser entre 0.01 y 100.00")]
    public decimal Price { get; set; }

    [DisplayName("URL de cubierta")]
    [StringLength(1024)]
    public string AlbumArtUrl { get; set; }

    public virtual Artist Artist { get; set; }
    public virtual Genre Genre { get; set; }
    public virtual ICollection<OrderDetail> OrderDetails
            { get; set; }
  }
}

 

Al final, obtuve un modelo usando código primero de EF para la aplicación. Les recomiendo seguir las guías prácticas para ver el progreso gradual, comenzando con clases simples de 2 o 3 propiedades y luego agregando más elementos hasta abarcar el esquema de datos completo.

 

John Galloway

 

Etiquetas asignadas:
 

4 Respuestas a “Generando un modelo de clases en EF a partir de una base datos usando código primero”

  1. Jorge dice:

    Hola, te hago una consulta. Puedo crear la base de datos solo con código, en cualquier momento que se esté ejecutando el programa…? Ya tengo el modelo edmx generado con el Diseñador, pero quiere crear la base de datos en tiempo de ejecución y con el nombre que quiera. Es posible…? Desde ya muchas gracias. Jorge

  2. Anónimo dice:

    Gracias por la información!, fue de mucha utilidad!..

  3. Genaro RIco dice:

    Gracias me parece muy interesante, no sabia nada de entity framerwork, solo tengo una duda como podria en grid cargar la tabla con estoy consultando y el nombre de la relacion que la llama (ejemplo) listo hijos y quiero el nombre de la madre algo asi. saludos gracias

Responder a



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.