Entity Framework Core'da otomatik veritabanı oluştur


110

.NET çekirdeğine taşınan uygulamam SQLite ile yeni EF Core'u kullanacak. Uygulama ilk çalıştırıldığında veritabanı ve tablo yapılarını otomatik olarak oluşturmak istiyorum. EF çekirdek belgelerine göre bu, manuel komutlar kullanılarak yapılır

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Ancak son kullanıcının bu komutları girmesini istemiyorum ve uygulamanın veritabanını ilk kullanım için oluşturmasını ve kurmasını tercih ederim. EF 6 için aşağıdaki gibi işlevler vardır:

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

Ancak EF Core'da bunlar var gibi görünmüyor. EF çekirdeği için eşdeğer bir şey hakkında herhangi bir örnek veya belge bulamıyorum ve EF çekirdek belgelerinde eksik özellikler listesinde bahsedilmiyor. Model sınıflarının kurulumunu zaten yaptım, bu yüzden veritabanını modellere göre başlatmak için bazı kodlar yazabilirim, ancak çerçeve bunu otomatik olarak yaparsa yığınlar daha kolay olurdu. Modeli otomatik olarak oluşturmak veya taşımak istemiyorum, sadece tablo yapılarını yeni bir veritabanında oluşturun.

Burada bir şey mi eksik yoksa EF çekirdeğinde otomatik tablo oluşturma işlevi eksik mi?

Yanıtlar:


158

Geçişleri oluşturduysanız, bunları Startup.cs dosyasında aşağıdaki gibi yürütebilirsiniz .

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

      ...

Bu, eklediğiniz geçişleri kullanarak veritabanını ve tabloları oluşturacaktır.

Entity Framework Geçişlerini kullanmıyorsanız ve bunun yerine yalnızca ilk çalıştırmada bağlam sınıfınızda olduğu gibi oluşturulmuş DbContext modelinize ihtiyacınız varsa, o zaman şunları kullanabilirsiniz:

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

      ...

Yerine.

Oluşturulduğundan emin olmadan önce veritabanınızı silmeniz gerekiyorsa şu numarayı arayın:

            context.Database.EnsureDeleted();

Sen aramadan hemen önce EnsureCreated()

Http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html?highlight=entity adresinden uyarlanmıştır.


1
EF için hala oldukça yeniyim, EF 6 kodunu kullanarak veri yapılarını tanımlayan sınıfları ilk olarak visual studio'dan geçerli bir veritabanı dosyası kullanarak "veritabanından oluştur" oluşturdum. Daha sonra bunları yeni dotnet core VS çözümüne kestim / yapıştırdım - bu yüzden sanırım bunlar geçişler değil. Bu, yukarıdaki kod kullanılmadan önce bir geçiş dosyası oluşturmam gerektiği anlamına mı geliyor?
deandob

2
Üzgünüm, cevabımda bir hata yaptım, geçişleri kullanmıyorsanız, context.Database.EnsureCreated () / EnsureDeleted () komutunu kullanabilirsiniz, daha fazla ayrıntı blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana

3
Ya her iki çözüme de ihtiyacınız varsa? Uygulamamızı UWP'ye taşıdık ve EF Core kullanmaya başladık, bu da bazı kullanıcıların DB'nin sıfırdan oluşturulmasına ihtiyaç duyduğu, bazılarının ise zaten DB'ye sahip olduğu anlamına geliyor. İlk geçişin yalnızca ilk tabloları zaten mevcut değilse oluşturmasını sağlamanın bir yolu var mı? Cevabınız bunu kapsamıyor gibi görünüyor veya bir şey mi kaçırıyorum?
Lars Udengaard

35

Cevabım Ricardo'nun cevabına çok benziyor, ancak yaklaşımımın biraz daha açık olduğunu hissediyorum çünkü onun usingişlevinde o kadar çok şey oluyor ki, daha düşük bir seviyede tam olarak nasıl çalıştığından bile emin değilim.

Dolayısıyla, sizin için başlık altında neler olduğunu tam olarak bildiğiniz bir veri tabanı oluşturan basit ve temiz bir çözüm isteyenler için, bu sizin için:

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

Bu hemen hemen, oluşturduğunuz içinde DbContext(bu durumda benimki çağrılır TargetsContext), Startup.cs uygulamanızda çalıştırıldığında DbContextsınıfta tanımlanan tabloların oluşturulmasını sağlamak için öğesinin bir örneğini kullanabileceğiniz anlamına gelir .


13
Tıpkı buradan bir bilgi olarak : EnsureCreatedtamamen geçişleri atlar ve sadece sizin için şemayı oluşturur, bunu geçişlerle karıştıramazsınız. EnsureCreatedher seferinde veritabanını bırakıp yeniden oluşturduğunuzda test etmek veya hızlı prototip oluşturmak için tasarlanmıştır. Taşıma işlemlerini kullanıyorsanız ve bunların uygulama başlangıcında otomatik olarak uygulanmasını istiyorsanız, context.Database.Migrate()bunun yerine kullanabilirsiniz .
Thomas Schneiter

Bu, bağlantı dizemin neden çalışmadığına dair kafa karışıklığımı cevaplıyor ... :( Yani veritabanı otomatik olarak oluşturulmadı ve DbContext kurucumda yaptığım Database.EnsureCreated () 'i belirtmelisiniz. Çok teşekkür ederim, beni 3 günlük ikilemden kurtardı. X_X
pampi

Bunu Başlangıç ​​dosyama yapıştırmayı denediğimi ve VS2019'un IHostingEnvironmentartık kullanımdan kaldırıldığını ve önerilen alternatifin Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z pls

18

İçeriği Startup.cs içindeki Configure parametre listesi aracılığıyla alırsanız, bunun yerine şunu yapabilirsiniz:

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

1
IMHO bu en iyi çözümdür: herhangi bir hizmeti veya hatta DB bağlamını önemsemeniz gerekmez, sadece bağımlılık enjeksiyonu yoluyla elde ettiğiniz içeriği kullanabilirsiniz. Güzel!
Tobias

15

EF Core 2.0+ için API'yi değiştirdikleri için farklı bir yaklaşım benimsemek zorunda kaldım. Mart 2019 itibarıyla Microsoft , veritabanı geçiş kodunuzu uygulama giriş sınıfınıza ancak WebHost oluşturma kodunun dışına koymanızı önerir.

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

Çalışma zamanında taşıma çalıştırıyorsanız, veritabanı şemasına yazmak için erişime sahip bir veritabanı bağlantısı kullanmanız gerekeceğini unutmayın. Bu yaklaşımı kullanırken, sorgularınız için geçişleri çalıştırmaktan farklı bir bağlantı kullanmanız önerilir. Bir SQL enjeksiyon saldırısı bir şekilde bunu başarırsa ve sorgularınız için DCL veya DDL izinlerine sahip bir bağlantı dizesi kullanıyorsanız, bu potansiyel bir saldırı vektörüdür. geeksforgeeks.org/sql-ddl-dql-dml-dcl-tcl-commands
Paul Stegler

8

Taşıma oluşturmadıysanız 2 seçenek vardır

1. Ana uygulamadan veritabanını ve tabloları oluşturun:

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

2. veritabanı zaten mevcutsa tabloları oluşturun:

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

Bubi'nin cevabına teşekkürler


3
hizmetlerin neler?
MichaelMao

Tüm ben "kullanmayın diyerek göçler etrafında yakalanan görünen koca uyarıları okuyorum belgeleri EnsureCreatedveya EnsureDeletedveya Database.Migratebaşarısız olacak"
mwilson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.