tự động tạo cơ sở dữ liệu trong Entity Framework Core


99

Ứng dụng của tôi đang được chuyển sang lõi .NET sẽ sử dụng lõi EF mới với SQLite. Tôi muốn tự động tạo cơ sở dữ liệu và cấu trúc bảng khi ứng dụng được chạy lần đầu tiên. Theo tài liệu cốt lõi của EF, điều này được thực hiện bằng các lệnh thủ công

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Tuy nhiên, tôi không muốn người dùng cuối nhập các lệnh này và muốn ứng dụng tạo và thiết lập cơ sở dữ liệu để sử dụng lần đầu. Đối với EF 6 có chức năng như

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

Nhưng trong EF Core, những điều này dường như không tồn tại. Tôi không thể tìm thấy bất kỳ ví dụ hoặc tài liệu nào về thứ gì đó tương đương cho lõi EF và nó không được đề cập trong danh sách các tính năng bị thiếu trong tài liệu lõi EF. Tôi đã thiết lập các lớp mô hình nên tôi có thể viết một số mã để khởi tạo cơ sở dữ liệu dựa trên các mô hình nhưng sẽ dễ dàng hơn nếu khung làm việc này tự động. Tôi không muốn tự động xây dựng mô hình hoặc di chuyển, chỉ cần tạo cấu trúc bảng trên cơ sở dữ liệu mới.

Tôi có thiếu thứ gì đó ở đây hay chức năng tự động tạo bảng bị thiếu trong lõi EF?

Câu trả lời:


146

Nếu bạn đã tạo các di chuyển, bạn có thể thực thi chúng trong Startup.cs như sau.

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

      ...

Điều này sẽ tạo cơ sở dữ liệu và các bảng bằng cách sử dụng di chuyển đã thêm của bạn.

Nếu bạn không sử dụng Entity Framework Migrations và thay vào đó chỉ cần mô hình DbContext của bạn được tạo chính xác như trong lớp ngữ cảnh của bạn lúc đầu chạy, thì bạn có thể sử dụng:

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

      ...

Thay thế.

Nếu bạn cần xóa cơ sở dữ liệu của mình trước khi đảm bảo rằng nó được tạo, hãy gọi:

            context.Database.EnsureDeleted();

Ngay trước khi bạn gọi EnsureCreated()

Phỏng theo: http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html?highlight=entity


1
Tôi vẫn còn khá mới với EF, tôi đã tạo các lớp xác định cấu trúc dữ liệu bằng cách sử dụng mã EF 6 trước tiên "tạo từ cơ sở dữ liệu" từ visual studio bằng cách sử dụng tệp cơ sở dữ liệu hiện tại. Sau đó, tôi cắt / dán những thứ này vào giải pháp dotnet core VS mới - vì vậy tôi đoán đây không phải là di chuyển. Điều đó có nghĩa là tôi phải tạo tệp di chuyển trước khi mã trên có thể được sử dụng?
deandob

2
Tôi xin lỗi, tôi đã mắc lỗi trong câu trả lời của mình, nếu bạn không sử dụng chuyển đổi, có thể sử dụng lệnh context.Database.EnsureCreate () / EnsureDeleted (), thêm chi tiết trong blog.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana

2
Điều gì xảy ra nếu bạn cần cả hai giải pháp? Chúng tôi vừa chuyển Ứng dụng của mình sang UWP và bắt đầu sử dụng EF Core, có nghĩa là một số người dùng cần DB được tạo từ đầu, trong khi những người khác đã có DB. Có cách nào để đảm bảo rằng lần di chuyển đầu tiên chỉ tạo ra các bảng ban đầu nếu chúng chưa tồn tại? Câu trả lời của bạn dường như không bao gồm điều này hoặc tôi đang thiếu một cái gì đó?
Lars Udengaard

33

Câu trả lời của tôi rất giống với câu trả lời của Ricardo, nhưng tôi cảm thấy cách tiếp cận của tôi đơn giản hơn một chút, đơn giản vì có quá nhiều thứ đang diễn ra trong usingchức năng của anh ấy mà tôi thậm chí không chắc nó hoạt động chính xác như thế nào ở cấp độ thấp hơn.

Vì vậy, đối với những người muốn có một giải pháp đơn giản và sạch sẽ tạo cơ sở dữ liệu cho bạn, nơi bạn biết chính xác những gì đang xảy ra, đây là giải pháp dành cho bạn:

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

Điều này có nghĩa là trong cái DbContextmà bạn đã tạo (trong trường hợp này, cái của tôi được gọi là TargetsContext), bạn có thể sử dụng một thể hiện của cái DbContextđể đảm bảo rằng các bảng được định nghĩa trong lớp được tạo khi Startup.cs được chạy trong ứng dụng của bạn.


10
Cũng giống như một thông tin từ đây : EnsureCreatedhoàn toàn bỏ qua di chuyển và chỉ tạo lược đồ cho bạn, bạn không thể trộn điều này với di chuyển. EnsureCreatedđược thiết kế để thử nghiệm hoặc tạo mẫu nhanh khi bạn có thể thả và tạo lại cơ sở dữ liệu mỗi lần. Nếu bạn đang sử dụng di chuyển và muốn chúng tự động áp dụng khi khởi động ứng dụng thì bạn có thể sử dụng context.Database.Migrate()thay thế.
Thomas Schneiter

Điều này giải đáp sự nhầm lẫn của tôi tại sao chuỗi kết nối của tôi không hoạt động ... :( Vì vậy, cơ sở dữ liệu không được tạo tự động mà bạn phải chỉ định Database.EnsureCreate () mà tôi đã thực hiện trong hàm tạo DbContext của mình. Cảm ơn bạn rất nhiều, đã giúp tôi thoát khỏi tình trạng khó xử 3 ngày. X_X
pampi

Tôi chỉ muốn lưu ý rằng tôi vừa thử dán cái này vào tệp Khởi động của mình và VS2019 đã thông báo cho tôi rằng IHostingEnvironmenthiện không được dùng nữa và giải pháp thay thế được đề xuất là Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z làm ơn

18

Nếu bạn nhận được ngữ cảnh thông qua danh sách tham số của Cấu hình trong Startup.cs, bạn có thể thực hiện việc này thay thế:

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

1
IMHO đây là giải pháp tốt nhất: bạn không phải quan tâm đến bất kỳ dịch vụ nào hoặc thậm chí là ngữ cảnh DB, bạn chỉ có thể sử dụng ngữ cảnh mà bạn nhận được thông qua chèn phụ thuộc. Đẹp!
Tobias

12

Đối với EF Core 2.0+, tôi phải thực hiện một cách tiếp cận khác vì họ đã thay đổi API. Kể từ tháng 3 năm 2019, Microsoft khuyến nghị bạn nên đặt mã di chuyển cơ sở dữ liệu của mình vào lớp mục nhập ứng dụng nhưng nằm ngoài mã xây dựng 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

Nếu bạn chưa tạo di chuyển, có 2 tùy chọn

1. tạo cơ sở dữ liệu và bảng từ ứng dụng Chính:

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

2. tạo bảng nếu cơ sở dữ liệu đã tồn tại:

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

Cảm ơn câu trả lời của Bubi


2
dịch vụ của bạn là gì?
MichaelMao

Tất cả các tài liệu tôi đang đọc chương trình cảnh báo lớn chất béo xung quanh di cư nói "Không sử dụng EnsureCreatedhoặc EnsureDeletedhoặc Database.Migratesẽ thất bại"
mwilson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.