Me gustaría ejecutar algún método LINQ en Up de migraciones. El problema es que no sé cómo puedo obtener la instancia de DbContext?
Este es el código generado por las migrations add
:
public partial class MyTableAddFieldTitle : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Title",
table: "MyTable",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Title",
table: "MyTable");
}
}
Me gustaría agregar algo así en el método Up
:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Title",
table: "MyTable",
nullable: true);
var context = ?????;
//Actual code is much more complicated, but the principle is the same.
foreach (var item in context.Set<DbMyTable>())
item.Title = item.SomeStringColumn;
context.SaveChanges();
}
¿El problema es cómo obtener instancia de contexto? Lo intenté con DI en constructor:
protected MyTableAddFieldTitle(MyContext context)
{
}
pero me sale un error
MissingMethodException: no se ha definido ningún constructor sin parámetros para este objeto. System.RuntimeTypeHandle.CreateInstance (tipo RuntimeType, bool publicOnly, ref bool canBeCached, ref RuntimeMethodHandleInternal ctor)
Encontré la solución.
En la clase de Startup
definí variable estática:
public static Func<MyContext> ContextFactory;
En constructor de clase de Startup
asigné variable:
public Startup(IHostingEnvironment env, IConfiguration config)
{
MyContext GetContext(IConfiguration configuration, IHostingEnvironment environment)
{
var builder = new DbContextOptionsBuilder<MyContext>();
builder.UseSqlServer(configuration["ConnectionStrings:Web"], b => b.MigrationsAssembly("Web.Hosting"));
if (environment.IsDevelopment())
builder.EnableSensitiveDataLogging();
return new MyContext(builder.Options);
}
ContextFactory = () => GetContext(config, env);
}
Luego en Migraciones simplemente llamo ContextFactory
:
var context = Startup.ContextFactory();
context.Set<DbMyTable>().Where(....
Para evitar que el campo de error no exista, creo 2 archivos de migración ( dotnet ef migrations add
).
Primero agrega campo:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Title",
table: "MyTable",
nullable: true);
}
Y segundo (vacío) ejecuta la consulta:
protected override void Up(MigrationBuilder migrationBuilder)
{
var context = Startup.ContextFactory();
context.Set<DbMyTable>().Where(....
}