Vorrei eseguire alcuni LINQ nel metodo Up delle migrazioni. Il problema è che non so come posso ottenere l'istanza di DbContext?
Questo è il codice generato dalle 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");
}
}
Vorrei aggiungere qualcosa del genere nel metodo 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();
}
Il problema è come ottenere l'istanza di contesto? Ho provato con DI in constructor:
protected MyTableAddFieldTitle(MyContext context)
{
}
ma ottengo errore:
MissingMethodException: nessun costruttore senza parametri definito per questo oggetto. System.RuntimeTypeHandle.CreateInstance (tipo RuntimeType, bool publicOnly, ref bool canBeCached, ref RuntimeMethodHandleInternal ctor)
Ho trovato una soluzione.
Nella classe di Startup
ho definito una variabile statica:
public static Func<MyContext> ContextFactory;
Nel costruttore della classe di Startup
ho assegnato una variabile:
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);
}
Quindi in Migrations, ho semplicemente chiamato ContextFactory
:
var context = Startup.ContextFactory();
context.Set<DbMyTable>().Where(....
Per evitare il campo di errore non esiste. Creo 2 file di migrazione ( dotnet ef migrations add
).
Primo campo aggiunto:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Title",
table: "MyTable",
nullable: true);
}
E la seconda (vuota) esegue la query:
protected override void Up(MigrationBuilder migrationBuilder)
{
var context = Startup.ContextFactory();
context.Set<DbMyTable>().Where(....
}