автоматическое создание базы данных в Entity Framework Core

103

Мое приложение, которое переносится на ядро ​​.NET, будет использовать новый EF Core с SQLite. Я хочу автоматически создавать структуры базы данных и таблиц при первом запуске приложения. Согласно основной документации EF, это делается с помощью ручных команд.

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Однако я не хочу, чтобы конечный пользователь вводил эти команды, и предпочел бы, чтобы приложение создавало и настраивало базу данных для первого использования. Для EF 6 есть такие функции, как

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

Но в EF Core их, похоже, не существует. Я не могу найти никаких примеров или документации по чему-то эквивалентному для ядра EF, и это не упоминается в списке недостающих функций в основной документации EF. У меня уже есть настроенные классы моделей, поэтому я мог бы написать код для инициализации базы данных на основе моделей, но было бы намного проще, если бы фреймворк делал это автоматически. Я не хочу автоматически строить модель или мигрировать, просто создайте структуры таблиц в новой базе данных.

Мне что-то здесь не хватает или в ядре EF отсутствует функция автоматического создания таблицы?

деандоб
источник

Ответы:

151

Если вы создали миграции, вы можете выполнить их в Startup.cs следующим образом.

 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();
      }

      ...

Это создаст базу данных и таблицы с использованием ваших добавленных миграций.

Если вы не используете Entity Framework Migrations, а вместо этого просто нуждаетесь в вашей модели DbContext, созданной точно так же, как в вашем классе контекста при первом запуске, вы можете использовать:

 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();
      }

      ...

Вместо.

Если вам нужно удалить свою базу данных, прежде чем убедиться, что она создана, позвоните:

            context.Database.EnsureDeleted();

Перед тем как позвонить EnsureCreated()

По материалам: http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html?highlight=entity

Рикардо Фонтана
источник
1
Я все еще новичок в EF, я создал классы, которые определяют структуры данных, используя код EF 6, сначала «создать из базы данных» из Visual Studio с использованием текущего файла базы данных. Затем я вырезал / вставил их в новое решение VS для ядра dotnet, так что я думаю, что это не миграции. Означает ли это, что мне нужно создать файл миграции, прежде чем можно будет использовать приведенный выше код?
deandob
2
Извините, я ошибся в своем ответе, если вы не используете миграции, можете использовать команду context.Database.EnsureCreated () / EnsureDeleted (), подробнее в blogs.msdn.microsoft.com/dotnet/2016 /
Рикардо Фонтана
2
Что делать, если вам нужны оба решения? Мы только что перенесли наше приложение на UWP и начали использовать EF Core, а это значит, что некоторым пользователям нужно создавать БД с нуля, а у других уже есть БД. Есть ли способ гарантировать, что первая миграция создаст только начальные таблицы, если они еще не существуют? Ваш ответ, кажется, не охватывает этого или я что-то упускаю?
Lars Udengaard
35

Мой ответ очень похож на ответ Рикардо, но я считаю, что мой подход немного проще просто потому, что в его usingфункции происходит так много всего, что я даже не уверен, как именно он работает на более низком уровне.

Итак, для тех, кто хочет простое и понятное решение, которое создает для вас базу данных, в которой вы точно знаете, что происходит под капотом, это для вас:

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

Это в значительной степени означает, что внутри DbContextсозданного вами (в данном случае моего называется мой TargetsContext), вы можете использовать экземпляр, DbContextчтобы гарантировать, что таблицы, определенные в классе, создаются при запуске Startup.cs в вашем приложении.

Susieloo_
источник
11
Так же, как информация отсюда : EnsureCreatedполностью обходит миграции и просто создает схему для вас, вы не можете смешивать это с миграциями. EnsureCreatedразработан для тестирования или быстрого прототипирования, когда вы можете каждый раз отбрасывать и заново создавать базу данных. Если вы используете миграции и хотите, чтобы они автоматически применялись при запуске приложения, вы можете использовать context.Database.Migrate()вместо них.
Thomas
Это отвечает на мое недоумение, почему моя строка подключения не работает ... :( Таким образом, база данных не создается автоматически, вы должны указать Database.EnsureCreated (), что я сделал в своем конструкторе DbContext. Большое спасибо, избавляет меня от трехдневной дилеммы. X_X
pampi
Просто хотел отметить, что я просто попытался вставить это в свой файл запуска, и VS2019 сообщил мне, что IHostingEnvironmentтеперь он устарел, а рекомендуемая альтернатива Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z, пожалуйста,
18

Если вы получили контекст через список параметров Configure в Startup.cs, вы можете вместо этого сделать следующее:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...
Джон Панкович
источник
1
IMHO, это лучшее решение: вам не нужно заботиться о какой-либо службе или даже о контексте БД, вы просто можете использовать контекст, который вы получаете через инъекцию зависимостей. Ницца!
Тобиас
13

Для EF Core 2.0+ мне пришлось использовать другой подход, потому что они изменили API. По состоянию на март 2019 года Microsoft рекомендует помещать код миграции базы данных в класс записи приложения, но за пределами кода сборки WebHost.

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>();
}
Пол Стеглер
источник
7

Если вы не создавали миграции, есть 2 варианта

1. создать базу данных и таблицы из приложения Main:

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

2. создайте таблицы, если база данных уже существует:

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

Благодаря ответу Буби

Натан Алард
источник
3
какие у вас услуги?
MichaelMao
Вся документация Читаю показывает большие жировые предупреждения вокруг миграции говорят : «Не использовать EnsureCreatedили EnsureDeletedили Database.Migrateне получится »
mwilson