Ich habe eine ASP.NET MVC 6-Anwendung und muss die Methoden Database.EnsureCreated
und aufrufen Database.Migrate
.
Aber wo soll ich sie anrufen?
Ich habe eine ASP.NET MVC 6-Anwendung und muss die Methoden Database.EnsureCreated
und aufrufen Database.Migrate
.
Aber wo soll ich sie anrufen?
Antworten:
Ich denke, das ist eine wichtige Frage und sollte gut beantwortet werden!
Was ist Database.EnsureCreated?
context.Database.EnsureCreated()
ist eine neue EF-Kernmethode, die sicherstellt, dass die Datenbank für den Kontext vorhanden ist. Wenn es existiert, wird keine Aktion ausgeführt. Wenn es nicht vorhanden ist, werden die Datenbank und ihr gesamtes Schema erstellt und es wird sichergestellt, dass es mit dem Modell für diesen Kontext kompatibel ist.
Hinweis:
Diese Methode verwendet keine Migrationen zum Erstellen der Datenbank. Darüber hinaus kann die erstellte Datenbank später nicht mithilfe von Migrationen aktualisiert werden. Wenn Sie auf eine relationale Datenbank abzielen und Migrationen verwenden, können Sie mithilfe der DbContext.Database.Migrate()
Methode sicherstellen, dass die Datenbank erstellt und alle Migrationen angewendet werden.
Wie haben wir das mit EF 6 gemacht?
context.Database.EnsureCreated()
entspricht den unten aufgeführten Ansätzen von EF 6:
Paketmanager-Konsole:
Enable-Migrations -EnableAutomaticMigrations. Add-Migration / Update-Datenbank.
Aus dem Code:
Database.SetInitializer CreateDatabaseIfNotExists
oder
Mit DbMigrationsConfiguration und setzen Sie AutomaticMigrationsEnabled = true;
Was ist Database.Migrate?
Wendet alle ausstehenden Migrationen für den Kontext auf die Datenbank an. Erstellt die Datenbank, falls sie noch nicht vorhanden ist.
Wie haben wir das mit EF 6 gemacht?
context.Database.Migrate()
entspricht den unten aufgeführten Ansätzen von EF 6:
Paketmanager-Konsole:
Update-Database -TargetMigration
Mit einer benutzerdefinierten DbMigrationsConfiguration:
AutomaticMigrationsEnabled = false; oder mit DbMigrator.
Fazit :
Wenn Sie Migrationen verwenden, gibt es context.Database.Migrate()
. Wenn Sie keine Migrationen und nur eine schnelle Datenbank (normalerweise zum Testen) möchten, verwenden Sie context.Database.EnsureCreated () / EnsureDeleted ().
Database.Migrate()
Migrationen (falls erforderlich) erstellt werden und dann die darauf basierende Basis aktualisiert wird. Ähnlich wie bei der automatischen Migration in EF 6. Aber ich habe mich geirrt. Es werden nur vorhandene Migrationen (falls vorhanden) in der Datenbank angewendet.
Mit den Informationen, die James P und Bassam Alugili zur Verfügung stellten, fügte ich der Configure
Methode in der Startup
Klasse ( Startup.cs ) diese Codezeilen hinzu :
using (var scope =
app.ApplicationServices.CreateScope())
using (var context = scope.ServiceProvider.GetService<MyDbContext>())
context.Database.Migrate();
Nur als Vorwort sollten Sie dies von Rowan Miller lesen :
...
EnsureCreated
umgeht Migrationen vollständig und erstellt nur das Schema für Sie. Sie können dies nicht mit Migrationen mischen.EnsureCreated
wurde für Tests oder Rapid Prototyping entwickelt, bei denen Sie die Datenbank jedes Mal löschen und neu erstellen können. Wenn Sie Migrationen verwenden und diese beim Start der App automatisch anwenden möchten, können Sie siecontext.Database.Migrate()
stattdessen verwenden.
Nach beantworten hier müssen Sie fügen Globals.EnsureDatabaseCreated();
es zuStartup.cs
:
Startfunktion in Startup.cs :
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
if (env.IsDevelopment())
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
Configuration = builder.Build();
Globals.Configuration = Configuration;
Globals.HostingEnvironment = env;
Globals.EnsureDatabaseCreated();
}
Und definieren Sie Globals.EnsureDatabaseCreated()
wie folgt:
public static void EnsureDatabaseCreated()
{
var optionsBuilder = new DbContextOptionsBuilder();
if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:DataContext"]);
else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:DataContext"]);
else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:DataContext"]);
var context = new ApplicationContext(optionsBuilder.Options);
context.Database.EnsureCreated();
optionsBuilder = new DbContextOptionsBuilder();
if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:TransientContext"]);
else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:TransientContext"]);
else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:TransientContext"]);
new TransientContext(optionsBuilder.Options).Database.EnsureCreated();
}
Zur Verwendung context.Database.Migrate()
siehe hier oder hier .
Globals
. Dies scheint eine nicht standardmäßige Methode zu sein, um dies zu verhindern
Normalerweise DbContext
wird das dem Abhängigkeitsinjektionsbehälter folgendermaßen hinzugefügt Startup.ConfigureServices()
:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add DbContext to the injection container
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
}
Der fungiert IServiceCollection
jedoch nicht als Dienstanbieter, und da der vor dem aktuellen Bereich ( ) DbContext
nicht beim Injektionscontainer registriert wurde , können wir hier nicht über die Abhängigkeitsinjektion auf den Kontext zugreifen.Startup.ConfigureServices
Henk Mollema bespricht manuell lösen Dienste während des Starts hier , aber erwähnt , dass ...
Das manuelle Auflösen von Diensten (auch bekannt als Service Locator) wird im Allgemeinen als Anti-Pattern angesehen ... [und] Sie sollten dies so weit wie möglich vermeiden.
Henk erwähnt auch, dass die Startup
Abhängigkeitsinjektion des Konstruktors sehr begrenzt ist und keine in konfigurierten Dienste enthält Startup.ConfigureServices()
, sodass die Verwendung von DbContext über den im Rest der App verwendeten Injektionscontainer am einfachsten und am besten geeignet ist.
Die Laufzeit der Hosting - Service - Provider können bestimmte Dienste in den Konstruktor der injizieren
Startup
Klasse, wieIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
in Pre-3.0 - Versionen),ILoggerFactory
undIServiceProvider
. Beachten Sie, dass letztere eine von der Hosting-Schicht erstellte Instanz ist und nur die wesentlichen Dienste zum Starten einer Anwendung enthält.
Um anzurufen Database.EnsureCreated()
oder Database.Migrate()
, können und möchten wir den DbContext automatisch auflösen lassen Startup.Configure()
, wo unsere konfigurierten Dienste jetzt über DI verfügbar sind:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add DbContext to the injection container
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyDbContext context)
{
if (env.IsDevelopment())
{
context.Database.EnsureCreated();
//context.Database.Migrate();
}
}
}
Bitte denken Sie daran , wie Bassam Alugili Antwort von EF Core - Dokumentation verwiesen , dass Database.EnsureCreated()
und Database.Migrate()
nicht zusammen sein sollen verwendet , da stellt man sicher , Ihre bestehende Migrationen auf die Datenbank angewendet werden, die bei Bedarf erstellt wird. Die andere Methode stellt lediglich sicher, dass eine Datenbank vorhanden ist, und erstellt, falls nicht, eine Datenbank, die Ihre Datenbank widerspiegelt DbContext
, einschließlich aller über die Fluent-API im Kontext vorgenommenen Seeding-Vorgänge.