26

Tôi có một ứng dụng MVC4 mà gần đây tôi đã nâng cấp lên Entity Framework 5 và tôi đang cố gắng chuyển cơ sở dữ liệu sang sử dụng di chuyển từ kiểu phát triển thả và tạo mỗi lần chạy.Entity Framework 5 Di chuyển: Thiết lập di chuyển ban đầu và hạt giống đơn của cơ sở dữ liệu

Đây là những gì tôi đã thực hiện trong chức năng khởi động ứng dụng của mình.

protected void Application_Start() 
{ 
    Database.SetInitializer(
     new MigrateDatabaseToLatestVersion< MyContext, Configuration >()); 
    ... 
} 

Tôi chạy lệnh Enable-Migrations về dự án kho của tôi và tôi nghĩ rằng điều này sẽ tạo ra một tập tin di chuyển ban đầu tuy nhiên các tập tin duy nhất nó tạo ra là Configuration

Khi tôi xóa cơ sở dữ liệu nó tạo ra nó như mong đợi qua mã đầu tiên và hạt giống cơ sở dữ liệu từ tệp cấu hình. Trong tệp cấu hình, tôi đã thay đổi tất cả các chức năng Add() thành AddOrUpdate()

Tuy nhiên, nó chạy chức năng hạt giống trong tệp Configuration mỗi khi trang web bắt đầu và sao chép tất cả dữ liệu hạt giống lặp đi lặp lại.

tôi tưởng tượng rằng nó sẽ tạo ra một tập tin initial migration như blog tôi đọc gợi ý rằng nó sẽ và tôi có thể đưa dữ liệu hạt giống trong đó nhưng nó đã không

bất cứ ai có thể giải thích làm thế nào tôi nên được thiết lập DB trong mã để nó chỉ có hạt giống một lần?


LINK: The migrations blog post I followed


Trong khi điều này là khá thú vị để sử dụng migrate.exe EF Tôi đã kể từ khi chuyển sang sử dụng roundhouse để chạy di cư. Tôi vẫn sử dụng EF để dàn dựng di chuyển của tôi dựa trên các mô hình nhưng tôi đã viết một ứng dụng giao diện điều khiển nhỏ để ghi các di chuyển ra các tệp SQL. Sau đó tôi sử dụng nhà tròn để thực hiện việc di trú thông qua các kịch bản xây dựng cào của tôi. Có quá trình liên quan nhiều hơn một chút nhưng ổn định hơn nhiều so với sử dụng EF để thực hiện di chuyển khi ứng dụng khởi động.

Trả lời

38

Điều này đã được chứng minh là một bài đăng phổ biến vì vậy tôi đã cập nhật nó theo thông tin phản hồi từ những người khác. Điều chính cần biết là phương thức Seed trong lớp Configuration đang chạy MỌI thời gian mà ứng dụng khởi động, đó không phải là ý kiến ​​trong phương thức template ngụ ý. Xem câu trả lời từ một người nào đó tại Microsoft với số này post về lý do tại sao đó là - nhờ Jason Learmouth vì đã tìm ra điều đó.

Nếu bạn, như tôi, chỉ muốn chạy các cập nhật cơ sở dữ liệu nếu có bất kỳ di chuyển đang chờ xử lý nào thì bạn cần thực hiện thêm một chút công việc. Bạn có thể thấy rằng nếu có các di chuyển đang chờ xử lý bằng cách gọi migrator.GetPendingMigrations(), nhưng bạn phải làm điều đó trong ctor vì danh sách các di chuyển đang chờ xử lý sẽ bị xóa trước khi phương thức Seed được gọi. Các mã để thực hiện điều này, mà đi trong lớp Migrations.Configuration là như sau:

internal sealed class Configuration : DbMigrationsConfiguration<YourDbContext> 
{ 
    private readonly bool _pendingMigrations; 

    public Configuration() 
    { 
     // If you want automatic migrations the uncomment the line below. 
     //AutomaticMigrationsEnabled = true; 
     var migrator = new DbMigrator(this); 
     _pendingMigrations = migrator.GetPendingMigrations().Any(); 
    } 

    protected override void Seed(MyDbContext context) 
    { 
     //Microsoft comment says "This method will be called after migrating to the latest version." 
     //However my testing shows that it is called every time the software starts 

     //Exit if there aren't any pending migrations 
     if (!_pendingMigrations) return; 

     //else run your code to seed the database, e.g. 
     context.Foos.AddOrUpdate(new Foo { bar = true}); 
    } 
} 

Tôi phải chỉ ra rằng một số người đã đề nghị đặt mã hạt trong 'lên' mã chuyển đổi thực sự. Điều này làm việc, nhưng có nghĩa là bạn cần phải nhớ để đặt mã hạt giống trong mỗi di cư mới và nó khá khó nhớ vì vậy tôi sẽ không làm điều đó. Tuy nhiên nếu hạt giống của bạn thay đổi với mỗi di cư thì đó có thể là một cách tốt để đi.

+0

Tôi đoán nó chạy mỗi lần bởi vì đó là cách duy nhất họ có thể làm điều đó mà không thực sự phải thực hiện gieo vào sự di trú thực tế. Nếu mã hạt giống của bạn nằm bên trong Up() của quá trình di chuyển, nó sẽ chỉ chạy một lần và điều này trực quan hơn với tôi, vì thường bạn thực hiện một số thay đổi db và muốn thêm một số dữ liệu vào phần mới này của lược đồ – FRoZeN

+0

Nếu bạn không có bất kỳ di chuyển nào, phương thức hạt giống của bạn sẽ không bao giờ được chạy bằng phương thức này. Tôi cũng ngày nay thích làm giống trong di cư - theo cách đó tôi biết nó sẽ chỉ chạy một lần. – oldwizard

+0

Xin chào pcguru. Trong thực tế, bạn luôn có một sự di trú vì cơ sở dữ liệu ban đầu được coi là một di chuyển, nghĩa là nó di chuyển từ cơ sở dữ liệu không có cơ sở dữ liệu. Tuy nhiên tôi có thể thấy lợi ích của việc có hạt giống trong quá trình di cư. –

2

Đây là điều tôi đã tự hỏi về quá khứ. Tôi có một số bảng trong cơ sở dữ liệu của tôi mà có được dân cư trong sự kiện Seed của tôi, và bây giờ tôi chỉ kiểm tra xem một trong số chúng có trống trong phương thức Seed hay không. Nếu có hàng, phương thức Seed không chạy. Không phải là sai lầm, nhưng không phải là lừa.

+1

Điều này làm việc để ngăn chặn việc sao chép dữ liệu nhưng có vẻ như một chút của một giải pháp hacky thêm một mệnh đề thoát. Tôi sẽ để câu hỏi mở thêm vài ngày nữa để xem liệu có cách nào hay hơn để làm điều đó – Neil

+0

Tôi đồng ý đó là giải pháp hacky - nó không phải là lối thoát, thêm "Nếu không có hàng nào tồn tại thì hãy chèn một số". Sau đó bạn có thể lặp lại nó cho các bảng bổ sung mà bạn có thể cư trú trong quá trình di chuyển. – Richard

6

Bạn có thể thêm di chuyển theo cách thủ công và điền vào bằng bất kỳ mã nào bạn muốn? Trong bảng điều khiển quản lý gói chạy:

Add-Migration [Name] 

Sau đó, bạn có thể chỉnh sửa tệp được tạo cho bạn trong thư mục di chuyển của mình.

Trong dự án của tôi, tôi thực sự làm giống như Richard mặc dù trong phương pháp Seed của cấu hình ngữ cảnh. Tôi thực sự không có sở thích. Nhưng việc di chuyển sẽ hiệu quả hơn ở chỗ ứng dụng không cần kiểm tra xem các hàng tồn tại trong cơ sở dữ liệu khi ứng dụng bắt đầu. Chỉ cần kiểm tra xem việc di chuyển có được chạy hay không, điều này sẽ nhanh hơn.

internal sealed class Configuration : DbMigrationsConfiguration<MyContext> 
{ 
    public Configuration() 
    { 
     // If you want automatic migrations as well uncomment below. 
     // You can use both manual and automatic at the same time, but I don't recommend it. 
     //AutomaticMigrationsEnabled = true; 
     //AutomaticMigrationDataLossAllowed = true; 
    } 

    protected override void Seed(MyContext context) 
    { 
     // This method will be called after migrating to the latest version. 

     // You can use the DbSet<T>.AddOrUpdate() helper extension method 
     // to avoid creating duplicate seed data. 

     context.FontFamilies.AddOrUpdate(
      f => f.Id, 
      new FontFamily { Id = 1, PcName = "Arial" }, 
      new FontFamily { Id = 2, PcName = "Times New Roman" }, 
     }); 

Tôi đang sử dụng tính năng này trong Toàn cầu.asax:

public class MvcApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     // Any migrations that haven't been applied before will 
     // automatically be applied on Application Pool restart 

     Database.SetInitializer<MyContext>(
      new MigrateDatabaseToLatestVersion<MyContext, 
      MyApp.Migrations.Configuration>() 
     ); 
    } 
} 
+0

Điều này sẽ được đánh dấu là câu trả lời. Gợi ý là tình trạng quá tải của "AddOrUpdate" với kiểm tra Primary Key. Tôi không nhận ra nó lần đầu tiên .. – Sven

2

Câu trả lời cho this SO question giải thích lý do tại sao Seed chạy mỗi khi ứng dụng chạy.

tôi sử dụng phương pháp Jon Smiths, nhưng tôi đã đưa việc kiểm tra cho cấp phát tuyên bố di cư trong một khối # nếu như thế này:

#if (!DEBUG) 
      if (!_pendingMigrations) return; 
#endif 

Bằng cách đó khi tôi gỡ lỗi các phương pháp Seed luôn chạy để repopulate của tôi dữ liệu về hạt giống - hữu ích khi tôi xóa trong khi thử nghiệm, v.v. nhưng tôi không nhận được thông tin hoàn hảo khi phát hành.

Các vấn đề liên quan