otomatis membuat database di Entity Framework Core

100

Aplikasi saya yang sedang di-porting ke .NET core akan menggunakan EF Core baru dengan SQLite. Saya ingin secara otomatis membuat database dan struktur tabel saat aplikasi dijalankan pertama kali. Menurut dokumentasi inti EF, hal ini dilakukan dengan menggunakan perintah manual

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Namun, saya tidak ingin pengguna akhir memasukkan perintah ini dan lebih suka aplikasi membuat dan menyiapkan database untuk penggunaan pertama. Untuk EF 6 ada fungsi seperti

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

Tapi di EF Core ini sepertinya tidak ada. Saya tidak dapat menemukan contoh atau dokumentasi apa pun tentang sesuatu yang setara dengan inti EF dan tidak disebutkan dalam daftar fitur yang hilang dalam dokumentasi inti EF. Saya sudah menyiapkan kelas model sehingga saya dapat menulis beberapa kode untuk menginisialisasi database berdasarkan model tetapi akan lebih mudah jika framework melakukan ini secara otomatis. Saya tidak ingin membuat model secara otomatis atau bermigrasi, cukup buat struktur tabel di database baru.

Apakah saya melewatkan sesuatu di sini atau apakah fungsi tabel buat otomatis hilang di inti EF?

deandob
sumber

Jawaban:

146

Jika Anda telah membuat migrasi, Anda dapat menjalankannya di Startup.cs sebagai berikut.

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

      ...

Ini akan membuat database dan tabel menggunakan migrasi yang Anda tambahkan.

Jika Anda tidak menggunakan Entity Framework Migrations, dan hanya ingin model DbContext Anda dibuat persis seperti di kelas konteks saat pertama kali dijalankan, Anda dapat menggunakan:

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

      ...

Sebagai gantinya.

Jika Anda perlu menghapus database Anda sebelum memastikannya dibuat, panggil:

            context.Database.EnsureDeleted();

Tepat sebelum Anda menelepon EnsureCreated()

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

Ricardo Fontana
sumber
1
Saya masih baru mengenal EF, saya membuat kelas yang mendefinisikan struktur data menggunakan kode EF 6 terlebih dahulu "buat dari database" dari studio visual menggunakan file database saat ini. Saya kemudian memotong / menempel ini ke solusi VS inti dotnet baru - jadi saya kira ini bukan migrasi. Apakah itu berarti saya harus membuat file migrasi sebelum kode di atas dapat digunakan?
deandob
2
Maaf, saya melakukan kesalahan dalam jawaban saya, jika Anda tidak menggunakan migrasi, dapat menggunakan konteks perintah.Database.EnsureCreated () / EnsureDeleted (), detail selengkapnya di blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana
2
Bagaimana jika Anda membutuhkan kedua solusi tersebut? Kami baru saja mem-porting Aplikasi kami ke UWP dan mulai menggunakan EF Core, yang berarti beberapa pengguna memerlukan DB untuk dibuat dari awal, sementara yang lain sudah memiliki DB. Adakah cara untuk memastikan bahwa migrasi pertama hanya membuat tabel awal jika belum ada? Jawaban Anda sepertinya tidak menutupi ini atau saya melewatkan sesuatu?
Lars Udengaard
33

Jawaban saya sangat mirip dengan jawaban Ricardo, tetapi saya merasa bahwa pendekatan saya sedikit lebih mudah karena ada begitu banyak hal yang terjadi dalam usingfungsinya sehingga saya bahkan tidak yakin bagaimana cara kerjanya pada level yang lebih rendah.

Jadi bagi mereka yang menginginkan solusi sederhana dan bersih yang membuat database untuk Anda di mana Anda tahu persis apa yang terjadi di balik terpal, ini untuk Anda:

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

Ini berarti bahwa di dalam DbContextyang Anda buat (dalam hal ini, milik saya disebut TargetsContext), Anda dapat menggunakan sebuah instance dari DbContextuntuk memastikan bahwa tabel yang ditentukan dengan di kelas dibuat saat Startup.cs dijalankan di aplikasi Anda.

susieloo_
sumber
10
Sama seperti informasi dari sini : EnsureCreatedbenar-benar mengabaikan migrasi dan hanya membuat skema untuk Anda, Anda tidak dapat mencampurnya dengan migrasi. EnsureCreateddirancang untuk pengujian atau pembuatan prototipe cepat di mana Anda tidak apa-apa dengan menjatuhkan dan membuat ulang database setiap saat. Jika Anda menggunakan migrasi dan ingin menerapkannya secara otomatis saat aplikasi dimulai, Anda dapat menggunakannya context.Database.Migrate().
Thomas Schneiter
Ini menjawab kebingungan saya mengapa string koneksi saya tidak berfungsi ... :( Jadi database tidak dibuat secara otomatis sehingga Anda harus menentukan Database.EnsureCreated () yang saya lakukan di konstruktor DbContext saya. Terima kasih banyak, selamatkan saya dari dilema 3 hari. X_X
pampi
Hanya ingin mencatat bahwa saya baru saja mencoba menempelkan ini di file Startup saya dan VS2019 memberi tahu saya bahwa IHostingEnvironmentsekarang sudah usang dan alternatif yang disarankan adalah Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z tolong
18

Jika Anda mendapatkan konteks melalui daftar parameter Configure di Startup.cs, Anda dapat melakukan ini:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...
John Pankowicz
sumber
1
IMHO ini adalah solusi terbaik: Anda tidak perlu peduli dengan layanan apa pun atau bahkan konteks DB, Anda cukup menggunakan konteks yang Anda dapatkan melalui injeksi ketergantungan. Bagus!
Tobias
13

Untuk EF Core 2.0+ saya harus mengambil pendekatan yang berbeda karena mereka mengubah API. Mulai Maret 2019 Microsoft menganjurkan Anda meletakkan kode migrasi database Anda di kelas entri aplikasi Anda tetapi di luar kode build 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>();
}
Paul Stegler
sumber
7

Jika Anda belum membuat migrasi, ada 2 opsi

1. buat database dan tabel dari aplikasi Main:

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

2. buat tabel jika database sudah ada:

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

Terima kasih atas jawaban Bubi

Nathan Alard
sumber
2
apa layananmu?
MichaelMao
Semua dokumentasi yang saya baca menunjukkan peringatan besar di sekitar migrasi yang mengatakan "Jangan gunakan EnsureCreatedatau EnsureDeletedatau Database.Migrateakan gagal"
mwilson