2012-02-18 16 views
41

He estado utilizando Entity Framework 4.3 en una base de datos existente y tengo un par de escenarios que estoy tratando de atender.La mejor forma de generar datos de forma incremental en Entity Framework 4.3

En primer lugar, si elimino mi base de datos, me gustaría que EF la recreara desde cero: he utilizado con éxito un inicializador de base de datos CreateDatabaseIfNotExists para esto.

En segundo lugar, si actualizo mi modelo y la base de datos ya existe, me gustaría que la base de datos se actualice automáticamente. Para esto he utilizado satisfactoriamente Migraciones de Entity Framework 4.3.

Así que esta es mi pregunta. Digamos que agrego una nueva tabla a mi modelo que requiere algunos datos de referencia, ¿cuál es la mejor manera de garantizar que estos datos se creen tanto cuando se ejecuta el inicio de la base de datos como cuando se ejecuta la migración? Mi deseo es que los datos se creen cuando estoy creando el archivo desde cero y también cuando la base de datos se actualice como resultado de una migración en ejecución.

En algunos ejemplos de migraciones EF he visto personas usar la función SQL() en el método UP de la migración para crear datos iniciales, pero si es posible preferiría usar el contexto para crear los datos iniciales (como se ve en la mayoría ejemplos de inicialización de base de datos) ya que me parece extraño que utilice sql puro cuando la idea completa de EF está abstrayendo eso. Intenté utilizar el contexto en el método UP pero, por alguna razón, no creía que existiera una tabla creada en la migración cuando intenté agregar los datos iniciales directamente debajo de la llamada para crear la tabla.

Cualquier sabiduría muy apreciada.

Respuesta

53

Si desea usar entidades para inicializar datos, debe usar el método Seed en su configuración de migraciones. Si genera nuevo proyecto Enable-Migrations obtendrá esta clase de configuración:

internal sealed class Configuration : DbMigrationsConfiguration<YourContext> 
{ 
    public Configuration() 
    { 
     AutomaticMigrationsEnabled = false; 
    } 

    protected override void Seed(CFMigrationsWithNoMagic.BlogContext context) 
    { 
     // This method will be called after migrating to the latest version. 

     // You can use the DbSet<T>.AddOrUpdate() helper extension method 
     // to avoid creating duplicate seed data. E.g. 
     // 
     // context.People.AddOrUpdate(
     //  p => p.FullName, 
     //  new Person { FullName = "Andrew Peters" }, 
     //  new Person { FullName = "Brice Lambson" }, 
     //  new Person { FullName = "Rowan Miller" } 
     // ); 
     // 
    } 
} 

La manera cómo no son muy eficientes migraciones de datos de semillas, ya que se supone que debe ser utilizado por alguna siembra muy básico. Cada actualización de la nueva versión pasará por un conjunto completo e intentará actualizar los datos existentes o insertar nuevos datos. Si no utiliza el método de extensión AddOrUpdate, debe asegurarse manualmente de que los datos se incluyan en la base de datos solo si aún no están presentes.

si usted quiere manera eficiente para la siembra, ya que debe sembrar o gran cantidad de datos que va a mejorar con el resultado común:

public partial class SomeMigration : DbMigration 
{ 
    public override void Up() 
    { 
     ... 
     Sql("UPDATE ..."); 
     Sql("INSERT ..."); 
    } 

    public override void Down() 
    { 
     ... 
    } 
} 
+8

En realidad se puede crear un contexto en el método y utilizar AddOrUpdate para insertar filas. Sin embargo, esto no estará incluido en la transacción de migración, por lo que puede causar problemas. Además, no se garantiza la compilación en el futuro cuando el modelo cambie. – Betty

+0

Intenté crear un contexto en el método Up, pero arrojó un error que decía que la tabla no existía. En su lugar, probaré SQL en el método "Arriba". –

+8

@Ladislav su profundidad de conocimientos sobre EF sigue de sorprenderme, ¿ha considerado autor de un libro sobre el tema y tal vez hacer frente a malentendidos comunes se encuentra con esta lista? – kingdango

32

no recomendaría el uso de Sql() llamadas en su método porque Up() (OMI) esto está realmente destinado al código de migración real para el cual no hay una función incorporada, en lugar de un código de semilla.

Me gusta pensar en los datos de inicialización como algo que podría cambiar en el futuro (incluso si mi esquema no), así que simplemente escribo comprobaciones "defensivas" de todos mis insertos en la función de inicialización para asegurarme de que la operación no se activó previamente.

Considere un escenario en el que tiene una tabla de "Tipos" que comienza con 3 entradas, pero luego agrega una 4ta. No debería necesitar una "migración" para solucionar esto.

El uso de Seed() también le brinda un contexto completo para trabajar, lo cual es mucho mejor que usar cadenas sencillas de sql en el método Sql() que demostró Ladislav.

Además, tenga en cuenta que el beneficio del uso de los métodos incorporados de EF, tanto para el código de la migración y el código de semilla es que sus operaciones de bases de datos siguen siendo independiente de la plataforma. Esto significa que los cambios en el esquema y las consultas se pueden ejecutar en Oracle, Postgre, etc. Si escribe SQL en bruto real, entonces potencialmente se podrá encerrar innecesariamente.

Usted podría ser menos preocupados por este ya que el 90% de las personas que utilizan EF sólo golpear siempre SQL Server, pero sólo estoy tirarla a la basura allí para darle una perspectiva diferente de la solución.

+7

creo que el método de "arriba" es un buen lugar para hacer los datos "de referencia" - datos de referencia por lo general implica la aplicación necesita que los datos para algún tipo de lógica. – nootn

Cuestiones relacionadas