automatisch database aanmaken in Entity Framework Core

Mijn applicatie die wordt geport naar .NET core zal de nieuwe EF Core met SQLite gebruiken. Ik wil automatisch de database- en tabelstructuren maken wanneer de app voor het eerst wordt uitgevoerd. Volgens de EF-kerndocumentatie wordt dit gedaan met behulp van handmatige commando’s

dotnet ef migrations add MyFirstMigration
dotnet ef database update

Ik wil echter niet dat de eindgebruiker deze opdrachten invoert en zou liever hebben dat de app de database maakt en instelt voor het eerste gebruik. Voor EF 6 is er functionaliteit zoals

Database.SetInitializer(new CreateDatabaseIfNotExists<MyContext>());

Maar in EF Core lijken deze niet te bestaan. Ik kan geen voorbeelden of documentatie vinden over iets dat gelijkwaardig is aan EF core en het wordt niet genoemd in de lijst met ontbrekende functies in de EF core documentatie. Ik heb de modelklassen al ingesteld, dus ik zou wat code kunnen schrijven om de database te initialiseren op basis van de modellen, maar het zou veel gemakkelijker zijn als het framework dit automatisch zou doen. Ik wil het model niet automatisch bouwen of migreren, maar maak gewoon de tabelstructuren in een nieuwe database.

Mis ik hier iets of ontbreekt de functie voor het automatisch maken van een tabel in EF core?


Antwoord 1, autoriteit 100%

Als u de migraties heeft gemaakt, kunt u ze als volgt in Startup.csuitvoeren.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
      using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
      {
            var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            context.Database.Migrate();
      }
      ...

Hiermee worden de database en de tabellen gemaakt met behulp van uw toegevoegde migraties.

Als u Entity Framework Migrations niet gebruikt en in plaats daarvan uw DbContext-model bij de eerste uitvoering precies zo wilt maken als in uw contextklasse, kunt u het volgende gebruiken:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
      using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
      {
            var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            context.Database.EnsureCreated();
      }
      ...

In plaats daarvan.

Als u uw database moet verwijderen voordat u zeker weet dat deze is gemaakt, belt u:

           context.Database.EnsureDeleted();

Vlak voordat je EnsureCreated()

aanroept

Aangepast van: http://docs.identityserver.io /en/latest/quickstarts/7_entity_framework.html?highlight=entity


Antwoord 2, autoriteit 20%

Mijn antwoord lijkt erg op het antwoord van Ricardo, maar ik heb het gevoel dat mijn aanpak iets eenvoudiger is, simpelweg omdat er zoveel gaande is in zijn functie usingdat ik niet eens zeker weet hoe precies het werkt op een lager niveau.

Dus voor degenen die een eenvoudige en schone oplossing willen die een database voor je creëert waarin je precies weet wat er onder de motorkap gebeurt, is dit iets voor jou:

public Startup(IHostingEnvironment env)
{
    using (var client = new TargetsContext())
    {
        client.Database.EnsureCreated();
    }
}

Dit betekent min of meer dat je binnen de DbContextdie je hebt gemaakt (in dit geval heet de mijne TargetsContext), een instantie van de DbContextom ervoor te zorgen dat de tabellen die zijn gedefinieerd met in de klasse worden gemaakt wanneer Startup.cswordt uitgevoerd in uw toepassing.


Antwoord 3, autoriteit 10%

Als u de context krijgt via de parameterlijst van Configure in Startup.cs, kunt u in plaats daarvan dit doen:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...

Antwoord 4, autoriteit 9%

Voor EF Core 2.0+ moest ik een andere aanpak kiezen omdat ze de API veranderden. Vanaf maart 2019 Microsoft raadt aanom uw databasemigratiecode in uw toepassingsinvoerklasse te plaatsen, maar buiten de WebHost-buildcode.

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();
        using (var serviceScope = host.Services.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetRequiredService<PersonContext>();
            context.Database.Migrate();
        }
        host.Run();
    }
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Antwoord 5, autoriteit 6%

Als u geen migraties heeft gemaakt, zijn er 2 opties

1.maak de database en tabellen vanuit het hoofdprogramma van de applicatie:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();

2.maak de tabellen als de database al bestaat:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>();
databaseCreator.CreateTables();

Dankzij Bubi’s antwoord


Antwoord 6

Als je zowel ZorgCreated als Migrate wilt, gebruik dan deze code:

    using (var context = new YourDbContext())
            {
                if (context.Database.EnsureCreated())
                {
                    //auto migration when database created first time
                    //add migration history table
                    string createEFMigrationsHistoryCommand = $@"
USE [{context.Database.GetDbConnection().Database}];
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
CREATE TABLE [dbo].[__EFMigrationsHistory](
    [MigrationId] [nvarchar](150) NOT NULL,
    [ProductVersion] [nvarchar](32) NOT NULL,
 CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY CLUSTERED 
(
    [MigrationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
";
                    context.Database.ExecuteSqlRaw(createEFMigrationsHistoryCommand);
                    //insert all of migrations
                    var dbAssebmly = context.GetType().GetAssembly();
                    foreach (var item in dbAssebmly.GetTypes())
                    {
                        if (item.BaseType == typeof(Migration))
                        {
                            string migrationName = item.GetCustomAttributes<MigrationAttribute>().First().Id;
                            var version = typeof(Migration).Assembly.GetName().Version;
                            string efVersion = $"{version.Major}.{version.Minor}.{version.Build}";
                            context.Database.ExecuteSqlRaw("INSERT INTO __EFMigrationsHistory(MigrationId,ProductVersion) VALUES ({0},{1})", migrationName, efVersion);
                        }
                    }
                }
                context.Database.Migrate();
            }

Other episodes