автоматично створювати базу даних в Entity Framework Core


100

Моя програма, яка переноситься на .NET core, використовуватиме нову 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 відсутня функція автоматичного створення таблиці?

Відповіді:


146

Якщо ви створили міграції, ви можете виконати їх у 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 дотнет-ядра - тому, мабуть, це не міграції. Чи означає це, що я повинен створити файл міграції, перш ніж можна використовувати наведений вище код?
deandob

2
Вибачте, я допустив помилку у своїй відповіді, якщо ви не використовуєте міграції, можете скористатися командою context.Database.EnsureCreated () / EnsureDeleted (), докладніше в blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Рікардо Фонтана,

2
Що робити, якщо вам потрібні обидва рішення? Щойно ми перенесли наш додаток на UWP і почали використовувати EF Core, що означає, що деяким користувачам потрібно створити БД з нуля, тоді як інші вже мають БД. Чи є спосіб забезпечити, щоб перша міграція створювала початкові таблиці лише тоді, коли вони ще не існують? Здається, ваша відповідь не охоплює цього, чи мені чогось не вистачає?
Ларс Уденгаард,

33

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

Тож для тих, хто хоче простого та чистого рішення, яке створює для вас базу даних, де ви точно знаєте, що відбувається під капотом, це для вас:

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

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


10
Так само, як інформація звідси : EnsureCreatedповністю обходить міграції і просто створює схему для вас, ви не можете змішувати це з міграціями. EnsureCreatedпризначений для тестування або швидкого створення прототипів, де ви можете щоразу скидати та повторно створювати базу даних. Якщо ви використовуєте міграції і хочете, щоб вони автоматично застосовувались під час запуску програми, тоді ви можете використовувати їх context.Database.Migrate().
Thomas Schneiter

Це відповідає моїй плутанині, чому мій рядок підключення не працює ... :( Тож база даних не створюється автоматично, тому ви повинні вказати Database.EnsureCreated (), що я зробив у своєму конструкторі DbContext. Велике спасибі, позбавляє мене від дилеми 3 днів. X_X
пампі

Просто хотів зазначити, що я просто спробував вставити це у свій файл запуску, і VS2019 повідомив мене, що IHostingEnvironmentзараз застарілий і рекомендована альтернатива Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z pls

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

Завдяки Буби в відповідь


2
які ваші послуги?
MichaelMao

Вся документація Читаю показує великі жирові попередження навколо міграції кажуть : «Не використовувати EnsureCreatedабо EnsureDeletedчи Database.MigrateНЕ вийде »
mwilson
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.