Puntos de datos

Preparándonos para Entity Framework 7

Julie Lerman

Julie LermanEl desarrollo de la próxima versión de Entity Framework está en camino. Puede echar un primer vistazo en qué estaba trabajando el equipo de EF en TechEd North America 2014, cuando el Administrador de programas Rowan Miller habló sobre los objetivos de Entity Framework 7 (EF7) y demostró algunos de los primeros fragmentos.

Eso fue hace cinco meses, mientras escribo esta columna, y aunque EF7 es aún una versión alfa, ya ha recorrido un largo camino. En esta columna, deseo hacerles saber que lo que EF7 le aportará a los programadores, los motivos detrás de las decisiones que se están tomando sobre EF7 y qué significa esta versión para las aplicaciones existentes que usan EF6 o versiones anteriores. También echaré un vistazo a cómo se verá parte del código.

Código abierto, pero ahora en GitHub

Lo primero que se debe saber sobre EF7 es que, al igual que EF6 es de código abierto. Pero en lugar de desarrollarse sobre CodePlex, EF7 lo hace sobre GitHub, junto con el resto de la próxima versión de ASP.NET. La URL para el desarrollo de EF7 es github.com/aspnet/EntityFramework. Al igual que con EF6, podrá ver los detalles de EF7 durante su evolución. Puede explorar el código, y también su progreso a través de las bifurcaciones y confirmación, seguir los debates, presentar problemas, bifurcar el código y enviar solicitudes de extracción para que el equipo examine y potencialmente confirme la base de código.

EF6 no va a despedirse pronto

No se preocupe, no estará obligado a pasar a EF7. Recuerde los DaSets y DataReaders ADO.NET. De forma similar a los formularios web ASP.NET, que aún son compatibles e incluso se benefician de otras modificaciones, ADO.NET continúa siendo parte de Microsoft NET Framework, aunque EF haya sido la principal tecnología de acceso a datos para .NET durante años. No se ha hecho mucho por mejorar esas tecnologías, pero continúan aquí y aún son compatibles con muchos códigos heredados (el mío incluido). Una de las ventajas más importantes que EF6 ofrece sobre otras tecnologías es que tiene un código abierto, entonces aunque el equipo de Microsoft no haga grandes inversiones en EF6, la comunidad podrá continuar usándolo. Además, el equipo de EF se encuentra comprometido con EF6. Continuarán haciendo modificaciones, inspeccionado de cerca las solicitudes de extracción y actualizando EF6. Pese a que se han ocupado principalmente de EF7 durante una buena parte de 2014, se actualizó EF6. La versión 6.1.0 se lanzó en febrero de 2014; la versión 6.1.1 en junio de 2014 y, mientras escribo este artículo, 6.1.2 se encuentra en versión beta y se lanzará pronto. Al comienzo estaba preocupado, pero ahora ya no, acerca de poder mantener aplicaciones más viejas en funcionamiento. Las únicas que me preocupan son las primeras aplicaciones que usaban EF con .NET Framework 3.5, ObjectContext, etc. Pero si no ha actualizado esas aplicaciones para aprovechar todas sus excelentes mejoras en EF con el paso de los años, posiblemente no se preocupe demasiado por EF7, de todos modos. También puede encontrar todos los paquetes anteriores para EF en NuGet, remontándose a EF 4.1.10311.

EF7: La lista es corta

Aquí presentamos la vista de alto nivel de aquello que resulta emocionante en EF7:

  • Compatibilidad con almacenes de datos no relacionales e incluso datos en memoria para pruebas.
  • Compatibilidad con máquinas y dispositivos que no usan el .NET Framework completo. Esto significa que puede usar EF7 EN aplicaciones Windows Phone y Windows Store, y también en máquinas Linux y Macintosh que ejecuten Mono.
  • Compatibilidad con muchas funciones que los programadores han solicitado pero que no podía lograrse con la base de código existente.
  • Compatibilidad continua con aplicaciones que usan el .NET Framework completo, como Windows Presentation Foundation y otras aplicaciones cliente.
  • EF7 se distribuirá de la misma manera que ASP.NET 5 y se puede usar con aplicaciones ASP.NET 5.

Superficie de codificación conocida, nueva base de código

En cada versión EF ha evolucionado el marco, lo que le agrega más capacidades, ajuste de rendimiento y API. Tal como lo escribí antes en esta columna y también en el artículo de información general del número de diciembre de 2013, “Entity Framework 6: La edición ninja” (bit.ly/1cwjyCD), la última versión llevó a EF a un nuevo nivel que le proporciona al marco muchas de las características que los usuarios han estado pidiendo todo este tiempo, como la ejecución de bases de datos asíncronas, el acceso a la canalización de consultas, la personalización de convenciones de Code First y mucho más. Explore en mayor profundidad estas características en mi curso Pluralsight, “Entity Framework 6, edición ninja: Novedades de EF6” (bit.ly/PS-EF6).

Había incluso muchas más características que los programadores deseaban para EF que Microsoft estaba ansioso por implementar, pero la base de código de más de 10 años de antigüedad sobre la que está creado EF, con una dependencia continua en ObjectContext y patrones de codificación menos flexibles, impidieron que el equipo pase al próximo nivel de capacidades. Se tomó una decisión difícil, que seguramente muchos de ustedes han debido enfrentar con su propio software heredado, para reconstruir Entity Framework desde cero.

EF7 no es crear un nuevo marco para el acceso a los datos. Se trata, en cambio, de crear una nueva base más sostenible sobre la que se pueda ofrecer compatibilidad no solamente con las características y el flujo de trabajo de los que ha dependido durante años con EF, sino también una que le permita mucho más. El equipo ha tenido problemas acerca de si este debía ser el próximo EF o una tecnología de acceso a datos nueva. En un punto, hasta me pregunté si sería “EF Light”. Sin embargo, la funcionalidad de EF está aún allí y, después de mucho pensarlo, acepto que tiene sentido considerarla la próxima versión de Entity Framework. Puede leer más al respecto en la publicación del blog del equipo, “EF7: ¿v1 o v7?” (bit.ly/1EFEdRH).

Sacarse de encima parte de lo heredado, conservando lo bueno

No obstante, también hay noticias sobre EF7 que preocupan a algunos programadores. Si bien las clases, los patrones y los flujos de trabajo más comunes de EF permanecerán intactos, algunos de los miembros menos usados quedarán en el camino. Por favor, no entren en pánico, desarrollaré este tema en mayor profundidad en un momento.

Permitir a los programadores continuar usando patrones familiares e incluso poder transportar una buena cantidad de código existente a EF7, era un objetivo fundamental. Podrá seguir utilizando DbContext, consultas de DbSet, LINQ, SaveChanges y muchos de los medios de interacción que han formado parte de EF durante mucho tiempo.

A continuación, un DbContext clase I definido en EF7:

public class BreweryContext : DbContext {
  public DbSet<Brewery> Breweries { get; set; }
  public DbSet<Beer> Beers { get; set; }
}

Además, existe una simple actualización en EF7 que es igual a la de EF6. Estoy usando un almacenamiento sincrónico, pero también están allí los métodos asíncronos:

public void StoreBeers(List<Beer> beers) {
  using (var context = new BreweryContext()) {
    context.Beers.AddRange(beers);
    context.SaveChanges();
  }
}

Una consulta simple:

using (var context = new BreweryContext()) {
       return context.Breweries.Where(b=>b.Location.Contains("Vermont"));
}

Estoy usando la versión de EF7 que viene en el paquete con la versión beta2-11616. EF7 no es realmente beta en este momento, pero “beta2” no está relacionado con la decisión de designación de nombre del paquete NuGet. Para el momento en que se publique este artículo EF7 habrá evolucionado aún más, por lo tanto, considérelo como un análisis, no una promesa.

Aún tengo un DdContext y defino DdSets como siempre lo he hecho. OnModelCreating continúa estando allí, aunque aquí no lo uso.

EF4.1 presentó DbContext API, que se centraba mucho más en el uso típico de EF. Por debajo, aún se depende del ObjectContext original que ofrece interacción con la base de datos, administra las transacciones y realiza un seguimiento del estado de los objetos. Desde entonces, DbContext se ha convertido en la clase de uso predeterminado y caería a un API de nivel inferior si deseara hacer una rara interacción con el ObjectContext. EF7 va a deshacerse de estos ObjectContext obesos; solo conservará los DbContext. Pero aún se puede acceder a algunas de las tareas en las que confió para ObjectContext.

Algunas de las asignaciones más complicadas que no ofrecen compatibilidad y que no se usan habitualmente desaparecerán con EF7. La publicación de blog que se mencionó anteriormente dice, “Por ejemplo, podría contar con un jerarquía de herencia que combinase asignaciones TPH, TPT y TPC, además de Separación de entidad, todo en la misma jerarquía”. Si alguna vez intentó trabajar directamente con la API MetadataWorkspace y salió corriendo, sabe que se trata de una bestia intrincada y compleja, útil para poder ofrecer este tipo de flexibilidad. Pero esa complejidad le impidió al equipo poder ofrecer la compatibilidad con otros escenarios que los usuarios han solicitado. Al simplificar las posibilidades de asignación, la API MetadataWorkspace también se simplificó y se hizo mucho más flexible. Puede llegar fácilmente a los metadatos de su esquema de modelo a partir de la API DbContext en EF7, lo que le ofrece capacidad de bajo nivel para llevar a cabo técnicas avanzadas sin tener que contar con el ObjectContext de bajo nivel a su disposición.

Se interrumpe EDMX, pero continuará Database First

Entity Framework actualmente tiene dos formas de describir un modelo. Uno usa un EDMX en el diseñador; el otro involucra las clases, un DbContext y asignaciones que utilizan las API de Code First. Si está usando el EDMX y el diseñador, en el momento de la ejecución EF crea un modelo en memoria a partir del XML detrás de EDMX. Si elige la ruta de Code First, EF crea el mismo modelo en la memoria al leer los DbContext y las asignaciones de las clases que proporcionó. Desde ese punto de vista, EF funciona de la misma manera, independientemente de cómo describa su modelo. Tenga en cuenta que con el flujo de trabajo de EDMX/Designer, también obtiene clases de POCO y un DbContext para que funcione con el código. Pero, dado que EDMX está allí, no se utilizan para crear ese modelo en memoria. Es importante comprenderlo mientras lee las siguientes oraciones: EF7 no admitirá el modelo EDMX basado en el diseñador. No tendrá la capacidad de leer el XML de EDMX en el momento de la ejecución para crear el modelo en memoria. Utilizará solamente el flujo de trabajo de Code First.

Cuando el equipo escribió en el blog sobre esto, generó pánico entre los programadores. En parte esto se debía al hecho de que muchos aún no se dan cuenta de que puede aplicar ingeniería inversa a una base de datos para clases de POCO, DbContext y asignaciones. En otras palabras, puede comenzar con una base de datos para obtener un modelo de Code First. Esto ha sido posible desde que se lanzó por primera vez EF Power Tools Beta a principios de 2011. Es compatible con el diseñador de EF6.1 y definitivamente será compatible con EF7. He dicho muchas veces que el mote “Code First” (Código primero) es un poco confuso y engañoso. Originalmente se llamaba “Code Only” (Solo código), pero el nombre se cambió a “Code First” para que coincidiera con “Database First” y “Model First.”

Por lo tanto, no necesita el diseñador ni un EDMX que se inicie con una base de datos existente.

Pero, ¿qué sucede si cuenta con modelos EDMX existentes y no desea perder la posibilidad de usar un diseñador? Existen otros diseñadores que admiten Entity Framework, como LLBLGen Pro Designer, que ya es compatible con EF Code First (bit.ly/11OLlN2) y Devart Entity Developer (bit.ly/1yHWbB2). Busque esas herramientas y posiblemente otras que puedan proporcionar compatibilidad de diseñador con EF7.

Sin embargo, existe otra alternativa a tener en cuenta: ¡quedarse con EF6!

Superficie más pequeña, más dispositivos y SO

Además, Microsoft se esforzó por optimizar la distribución de las API de EF. La carpeta del paquete NuGet para EF6.1.1 es de aproximadamente 22 MB. Esto incluye un ensamblado de 5,5 MB para .NET Framework 4.5 y otro en caso de que esté usando .NET Framework 4. Con EF7, existen algunas DLL más pequeñas. Se podrán combinar solamente las DLL necesarias para respaldar su flujo de trabajo. Por ejemplo, si tiene como objetivo SQL Server, utilizaría un EntityFramework.dll básico, una DLL para SQL Server y otro con las API comunes a los almacenes de datos relacionales. Si desea usar migraciones, ese es un ensamblado por separado que puede omitir. De lo contrario, es posible que desee crear y ejecutar migraciones desde la Consola del administrador de paquetes. Existe una API para comandos. Al utilizar el administrador de paquetes NuGet, se identificarán y se descargarán los paquetes adecuados a través de sus dependencias, para que no deba preocuparse por los detalles.

Lo que hace esto es minimizar el tamaño de EF7 en el ordenador o el dispositivo del usuario final, lo que es especialmente importante en los dispositivos. ASP.NET también va por este camino. Ambas tecnologías están dejando de confiar en .NET Framework completo. En cambio, solamente distribuirán las DLL necesarias para completar las tareas de una aplicación determinada. Esto significa que la versión ya optimizada de .NET que utilizan las aplicaciones Windows Phone y Windows Store podrán usar EF7.

También significa que los SO como OS X y Linux que usan Mono en lugar de .NET Framework completo, también podrán compatibilidad con Entity Framework del cliente.

Más allá de lo relacional

Cuando se presentó Entity Framework por primera vez, Microsoft creía que se estaba utilizando para diversos almacenes de datos, aunque la primera pasada se centraba en bases de datos relacionales. En ese momento existían bases de datos no relacionales, pero no se utilizaban masivamente, a diferencia de las bases de datos NoSQL, especialmente las bases de datos documentales, que son tan populares hoy.

Si bien EF es un asignador relacional de objetos (ORM), los programadores que lo usan pueden usar las mismas estructuras para que interactúen con bases de datos no relacionales. EF7 proporcionará compatibilidad de alto nivel para esto, pero recordará que significa realmente alto nivel. Existen vastas diferencias entre las bases de datos relacionales y las no relacionales y EF no hará ningún intento por enmascarar esas diferencias. Sin embargo, para las consultas y las actualizaciones básicas, podrá usar los patrones con los que ya está familiarizado.

La Figura 1 muestra el código de una aplicación de muestra que tiene como objetivo el almacenamiento de tablas de Microsoft Azure, que es una base de datos documental no relacional. La muestra proviene del Administrador de programas EF Rowan Miller en github.com/rowanmiller/Demo-EF7. Tenga en cuenta que la muestra se ejecuta con la versión 11514 de las versiones compiladas nocturnas alfa de EF7.

Figura 1 Un DbContext definido para que funcione con el almacenamiento de tablas de Azure

public class WarrantyContext : DbContext
{
  public DbSet<WarrantyInfo> Warranties { get; set; }
  protected override void OnConfiguring(DbContextOptions options) {
    var connection =
      ConfigurationManager.ConnectionStrings["WarrantyConnection"]
                        .ConnectionString;
    options.UseAzureTableStorage(connection);
  }
  protected override void OnModelCreating(ModelBuilder builder) {
    builder.Entity<WarrantyInfo>()
           .ForAzureTableStorage()
           .PartitionAndRowKey(w => w.BikeModelNo, w => w.BikeSerialNo);
  }
}

El método OnConfiguring es nuevo. Es una forma de afectar de qué manera EF configura DbContext en el momento de la ejecución, de manera similar a como puede hacerlo hoy con la clase de DbConfiguration. Tenga en cuenta el método de extensión builder.UseAzureTableStorage, que existe gracias a que también he instalado el paquete EntityFramework.AzureTableStorage en mi proyecto.

EF7 usa este patrón para sus diversos proveedores. A continuación, se presenta un método OnConfiguring en una clase de DbContext dentro de un proyecto que tiene como objetivo SQLite:

protected override void OnConfiguring(DbContextOptions builder) {
  string dir = ApplicationData.Current.LocalFolder.Path;
  string connection = "Filename=" + Path.Combine(dir, "VermontBrewery.db");
  builder.UseSQLite(connection);
}

Este proyecto tiene instalado el paquete EntityFramework.SQLite, por lo tanto, ahora en cambio tengo el método de extensión UseSQLite.

Volviendo a la clase WarrantyContext de la Figura 1, se puede ver el reemplazo conocido de OnModelCreating por DbContext y allí es donde voy a hacer algunas asignaciones especiales. Nuevamente, cuento con los métodos suministrados por el paquete EntityFramework.AzureTableStorage. Puedo elegir los paquetes que deseo en base a las características que necesito. El almacenamiento de tablas de Windows Azure depende de un par clave-valor de identidad única que es compatible con la partición de tablas. Para poder recuperar o almacenar datos, es fundamental saber qué valores se utilizarán para PartitionKey y RowKey, ya que la API proporciona un método (PartitionAndRowKey) que te permite asignar las propiedades a las claves correspondientes. El concepto no es diferente de la forma en la que se pudo usar la API fluida o las Anotaciones de datos para especificar la propiedad que se asigna la clave principal de una base de datos relacional.

Gracias a esta asignación, puedo escribir una consulta LINQ conocida para recuperar algunos datos:

var warranty = _context.Warranties
          .Where(w =>
            w.BikeModelNo == modelNo
            && w.BikeSerialNo == serialNo)
          .SingleOrDefault();

Entonces, está viendo una consulta LINQ típica, pero que se está ejecutando con el almacén de datos de Almacenamiento de tablas de Azure, de la misma manera que se lo puede hacer hoy con una base de datos relacional.

Esta misma demostración también actualiza los objetos de la garantía; crea e inserta nuevos con DbSet.Add y usa DbContextSaveChanges para conservar todo nuevamente en el almacén de datos, al igual que se hace hoy con EF6, y tal como se lo ha hecho a lo largo de la historia de EF.

También es interesante tener en cuenta de qué manera Entity Framework siempre ha admitido un conjunto de características canónicas para su asignación a bases de datos relacionales, pero dejó a consideración de los proveedores de bases de datos especificar cómo se traducirían a la base de datos de destino. EF7 contará con un conjunto de características canónicas de alto nivel que puede ser comprendido tanto por almacenes de datos relacionales como no relacionales. Existe también un conjunto de características de menor nivel que se centra en las bases de datos relacionales y que están encapsuladas en el ensamblado de EntityFramework.Relational. Todos los proveedores de bases de datos relacionales dependerán de ellos y, al igual que hoy, el manejo específico de la interacción de las bases de datos se alojará en las API del propio proveedor, como el EntityFramework.SQLite que use anteriormente. Podrá encontrar métodos de extensión en los proveedores que derivan de un método AsRelational, que se encuentra en la API relacional. Se trata de un método de extensión de DbContext.

Existe incluso un proveedor de almacenes de datos en memoria, que sirve para probar la unidad cuando se desea evitar la interacción con una base de datos que podría estar involucrada en la lógica que se está sometiendo a prueba. Como es típico en estos escenarios, se usan marcos falsos o simulados para representar la interacción de la base de datos.

Si configurara una prueba que ejecute una consulte o actualice la base de datos, tendría algún código para crear instancias de la base de datos, como:

using (var context = new BreweryContext()) {
  // Perform some action against the context
}

Se puede cambiar fácilmente por un almacenamiento en memoria instalando primero el paquete entityframework.InMemory en el proyecto de prueba, lo que define DbContextOption para InMemoryStore y luego, especificar que el contexto debe usar esa opción. Nuevamente, esto es posible gracias a métodos de extensión proporcionados por esta API:

var options = new DbContextOptions().UseInMemoryStore();
using (var context = new BreweryContext(options)){
  // Perform some action against the context
}

Más características, más capacidades, mayor flexibilidad

Ya se pueden ver los beneficios de la nueva base de código en la flexibilidad que proporcionan los métodos de extensión y en la posibilidad de afectar la canalización de Entity Framework con la sobrecarga de OnConfiguring. Existen puntos de extensibilidad en toda la nueva base de código, no solamente para cambiar EF7, sino para simplificarlo y que pueda aplicar su propia lógica a EF7.

La nueva base de código principal le ofrece al equipo de EF la oportunidad de solucionar algunos viejos problemas. Por ejemplo, la versión que estoy usando admite la actualización de lotes, que es la predeterminada para las bases de datos relacionales. He jugado con el código que me permite usar mis propios métodos en línea con las consultas de LINQ sin recibir el temido “Entity Framework cannot translate this method into SQL” (Entity Framework no puede traducir este método en SQL). En cambio, EF y los proveedores puede analizar qué parte de la consulta se convertirá en SQL y cuál será ejecutada localmente en el cliente. Estoy segura de que habrá protección y orientación para evitar ciertos problemas potenciales de rendimiento de esa característica en particular.

El equipo pudo agregar la capacidad de claves externas únicas que se solicitaban desde hacía mucho tiempo para los modelos. También están examinando detenidamente ofrecer compatibilidad con las funciones con valores de tabla y formas más claras de manejar los datos desconectados, que es algo en lo que me he centrado durante muchos años con Entity Framework. Es un problema común con las aplicaciones desconectadas, no simplemente cuando Entity Framework está involucrado, no es fácil crear algoritmos que funcionarán consistentemente en cada escenario. Por lo tanto, con seguridad se necesita un enfoque nuevo.

Hay mucho más por qué entusiasmarse con EF7. Recomiendo encarecidamente examinar de cerca las publicaciones del Blog del equipo de ADO.NET en blogs.msdn.com/adonet. Además de la publicación que mencioné antes, Rowan Miller escribió en profundidad sobre la decisión de dejar de ofrecer compatibilidad en EF7; consulte “EF7: ¿Qué significa realmente ‘Code First Only’” en bit.ly/1sLM3Ur. Eche un vistazo al blog, y también al proyecto GitHub. El wiki de GitHub (bit.ly/1viwqXu) tiene enlaces acerca de cómo acceder a compilaciones nocturnas; como descargar, compilar y depurar el código fuente; algunos análisis pormenorizados y notas de las reuniones de diseño. El equipo está ansioso por recibir comentarios y emocionado de recibir solicitudes de extracción.

Una decisión que no se tomó ligeramente.

Es importante escribir sobre EF7 para alejar algunos temores sobre un cambio tan grande y que algunas de las características existentes de EF que podrían ser integrales para sus aplicaciones no formarán parte de EF7. Estos temores no son infundados y el equipo no lo está tomando a la ligera, ni yo tampoco. Sin embargo, es fundamental saber que EF6 no desaparecerá y continuará evolucionando con aportes de la comunidad. Si desea aprovechar el avance, deberá realizar algunas elecciones difíciles. Actualizar grandes aplicaciones no será fácil y debe sopesar las opciones cuidadosamente. Quizás, puede dividir la aplicación, reescribiendo solamente algunas partes para beneficiarse de EF7.

Nuevamente, estoy escribiendo esta columna, EF7 se encuentra aún en sus primeras etapas y no estoy segura de cuánto tiempo pasará hasta que se lea. Pero el código actual disponible y los paquetes NuGet están aquí para explorar, experimentar con ellos y ofrecer comentarios. Tenga en cuenta que es posible que el equipo no siempre mantenga actualizadas todas las API del proveedor (como Redis, SQLite y otras) a medida que evoluciona la API principal. De acuerdo con la publicación de bit.ly/1ykagF0, “EF7: Prioridades, Foco y versión inicial,” la primera versión de EF7 se centrará en la compatibilidad con ASP.NET 5. En las versiones siguientes agregarán más características. Aun así, aunque EF7 no sea aún lo suficientemente estable para comenzar a compilar aplicaciones con él, definitivamente aquí hay suficiente para que comience a planificar a futuro.


Julie Lerman es una Microsoft MVP, mentora y consultora de .NET que vive en las colinas de Vermont. Puede encontrarla presentando el acceso a datos y otros temas de .NET a grupos de usuarios y en conferencias en todo el mundo. Ella realiza publicaciones en el blog thedatafarm.com/blog y es la autora de "Programming Entity Framework" (2010), así como de una edición de Code First (2011) y una edición de DbContext (2012), todos de O’Reilly Media. Sígala en Twitter en twitter.com/julielerman y vea sus cursos de Pluralsight en juliel.me/PS-Videos.

Gracias al siguiente experto técnico de Microsoft por revisar este artículo: Rowan Miller

Esto se basa en una versión alfa de Entity Framework 7. Toda la información está sujeta a cambios.