2011-06-10 21 views
62

Cơ sở dữ liệu được tạo thành công (giống như các bảng) nhưng không được tạo hạt giống. Tôi đã dành nhiều giờ và đọc rất nhiều bài viết nhưng không thể có được nó. Bất kỳ đề xuất?Làm thế nào tôi có thể lấy cơ sở dữ liệu của mình để tạo hạt giống bằng cách sử dụng Entity Framework CodeFirst?

Trên một lưu ý phụ, có thể gọi trình khởi tạo mà không cần tham chiếu đến DatabaseContext của tôi trong ứng dụng khách không?

Tôi đã bao gồm tất cả mã có liên quan mà tôi có thể nghĩ đến. Nếu bất cứ điều gì khác sẽ hữu ích, xin vui lòng cho tôi biết.

Những điều tôi đã thử:

  1. Tôi đã xóa chuỗi kết nối của tôi (vì nó mặc định là SQLEXPRESS anyways, chỉ tên đã thay đổi)
  2. tôi đã thay đổi DropCreateDatabaseIfModelChanges để DropCreateDatabaseAlways, vẫn như nhau.

Chỉnh sửa: Điều thực sự kỳ lạ là nó đã hoạt động một lần, nhưng tôi không biết làm thế nào hoặc tại sao nó lại phá vỡ. Tôi giả định các chuỗi kết nối, nhưng ai biết được.

DatabaseInitializer.cs

public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext> 
{ 
    protected override void Seed(DatabaseContext context) 
    { 
    // Seeding data here 
    context.SaveChanges(); 
    } 
} 

DatabaseContext.cs

public class DatabaseContext : DbContext 
{ 
    protected override void OnModelCreating(DbModelBuilder mb) 
    { 
    // Random mapping code 
    } 

    public DbSet<Entity1> Entities1 { get; set; } 
    public DbSet<Entity2> Entities2 { get; set; } 

} 

Global.asax.cs - Application_Start()

protected void Application_Start() 
{ 
    Database.SetInitializer<DatabaseContext>(new DatabaseInitializer()); 
    AreaRegistration.RegisterAllAreas(); 
    RegisterGlobalFilters(GlobalFilters.Filters); 
    RegisterRoutes(RouteTable.Routes); 
} 

Khách hàng web.config

<connectionStrings> 
    <add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" /> 
</connectionStrings> 

GIẢI PHÁP

Vì lợi ích của tài liệu, tôi đang chia sẻ giải pháp của mình ở đây. Điều hướng tất cả các bình luận sẽ là một nỗi đau. Cuối cùng tôi đã có DatabaseInitializer và DatabaseContext trong các lớp riêng biệt. Tôi không thực sự hiểu trong khi những thay đổi nhỏ bé này đã sửa nó, nhưng ở đây.

DatabaseInitializer.cs

public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext> 
{ 
    protected override void Seed(DatabaseContext context) 
    { 
    // Seed code here 
    } 
} 

DatabaseContext.cs

public class DatabaseContext : DbContext 
{ 
    public DatabaseContext() : base("MyDatabase") { } 

    protected override void OnModelCreating(DbModelBuilder mb) 
    { 
    // Code here 
    } 

    public DbSet<Entity> Entities { get; set; } 
    // Other DbSets 
} 

Global.asax.cs - Application_Start()

protected void Application_Start() 
{ 
    Database.SetInitializer(new DatabaseInitializer()); 
    AreaRegistration.RegisterAllAreas(); 
    RegisterGlobalFilters(GlobalFilters.Filters); 
    RegisterRoutes(RouteTable.Routes); 
} 
+0

Bạn có thêm các mục hạt giống với bối cảnh dữ liệu của bạn? Tôi biết tôi đã bỏ lỡ điều đó trước đây. –

+0

Vâng tôi. Cảm ơn bạn đã kiểm tra mặc dù :). – OpticalDelusion

+1

= D Không phải lo lắng. Bạn có thể đặt một điểm break trong mã và đảm bảo rằng Seed của bạn đang được gọi? –

Trả lời

36

Đây là những gì lớp DbContext của tôi tất cả như thế nào và họ gieo rắc tốt:

public class MyDbContext : DbContext 
{ 
    public DbSet<MyClass> MyClasses { get; set; } 

    protected override void OnModelCreating (DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating (modelBuilder); 
     modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>(); 

     // Add any configuration or mapping stuff here 
    } 

    public void Seed (MyDbContext Context) 
    { 
     #if DEBUG 
     // Create my debug (testing) objects here 
     var TestMyClass = new MyClass() { ... }; 
     Context.MyClasses.Add (TestMyClass); 
     #endif 

     // Normal seeding goes here 

     Context.SaveChanges(); 
    } 

    public class DropCreateIfChangeInitializer : DropCreateDatabaseIfModelChanges<MyDbContext> 
    { 
     protected override void Seed (MyDbContext context) 
     { 
      context.Seed (context); 

      base.Seed (context); 
     } 
    } 

    public class CreateInitializer : CreateDatabaseIfNotExists<MyDbContext> 
    { 
     protected override void Seed (MyDbContext context) 
     { 
      context.Seed (context); 

      base.Seed (context); 
     } 
    } 

    static MyDbContext() 
    { 
     #if DEBUG 
     Database.SetInitializer<MyDbContext> (new DropCreateIfChangeInitializer()); 
     #else 
     Database.SetInitializer<MyDbContext> (new CreateInitializer()); 
     #endif 
    } 
} 

Tôi đã sử dụng mô hình này một vài lần và nó đã làm việc rất tốt cho tôi.

+2

Đây không phải là giải pháp tôi đã triển khai chính xác, tôi đã giải thích chi tiết giải pháp của mình trong câu hỏi gốc ở trên. Chỉ cần đăng nhận xét này để dễ sử dụng cho người dùng trong tương lai. Nhờ jdangelo cho tất cả sự giúp đỡ! – OpticalDelusion

+1

Đây là một phương pháp tuyệt vời để thực hiện việc này vì nó không yêu cầu bất kỳ thay đổi nào đối với Application_Start() và do đó có thể sử dụng lại – xkingpin

0

Sự kiện hạt giống trong ví dụ của bạn sẽ chỉ bị sa thải một khi bạn sử dụng DropCreateDatabaseIfModelChanges, bạn có thể thay đổi điều này thành DropCreateDatabaseAlways i suy nghĩ và nó sẽ kích hoạt sự kiện hạt giống mỗi lần.

Sửa

Đây là DataContext của tôi

public WebContext() 
{ 
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>()); 
} 
+0

Tôi đã thử chuyển đổi. Không may mắn.Vẫn tạo ra cơ sở dữ liệu và tất cả các bảng nhưng không hạt giống. – OpticalDelusion

+0

Tôi gọi Database.SetInitializer (new DatabaseInitializer()); trong constructor của DatabaseContext mà làm việc cho tôi –

+0

Tôi không thể tham khảo DatabaseInitializer trong DatabaseContext vì đó sẽ là một tham chiếu vòng tròn. Ngoài ra nó không cần phải đi trong constructor DatabaseContext, vì nó sẽ được gọi bởi constructor DatabaseInitializer trong App_Start (theo như hiểu biết của tôi). – OpticalDelusion

0

Điều này chỉ xảy ra với tôi khi tôi đang khám phá Tính năng đầu tiên của mã. Tình huống này thường xảy ra khi bạn đã sử dụng Code First đầu tiên để tạo cơ sở dữ liệu của bạn mà không có bất kỳ chiến lược khởi tạo nào.

Nếu bạn quyết định thực hiện sau này bằng cách thực hiện chiến lược dựa trên DropCreateDatabaseIfModelChanges, nhưng không sửa đổi mô hình, thì phương pháp Seed sẽ không được gọi kể từ khi tạo cơ sở dữ liệu và chiến lược của bạn sẽ chỉ được áp dụng vào lần tiếp theo bạn thay đổi mô hình.

Nếu điều này xảy ra với bạn, chỉ cần cố gắng sửa đổi mô hình của bạn một chút để kiểm tra giả thuyết này và tôi đặt cược, cơ sở dữ liệu của bạn sẽ trở nên thông dụng;)

Tôi không có giải pháp nào, ngoại trừ sử dụng một chiến lược luôn tạo cơ sở dữ liệu, nhưng tôi thực sự không nhầm lẫn với việc đưa chiến lược khởi tạo vào DbContext của bạn vì lớp này là goind được sử dụng trong môi trường sản xuất của bạn, mặc dù chiến lược khởi tạo dường như chủ yếu được sử dụng để thông thạo môi trường phát triển.

10

phương pháp Seed của tôi không được viện dẫn ngay cả với cuộc gọi thích hợp để Database.SetInitializer trong Application_Start ... Lý do cho nó thật sự rất đơn giản: khởi tạo không được áp dụng ở tất cả nếu bạn chưa có bất kỳ mã mà thực sự sử dụng bối cảnh cơ sở dữ liệu.

2

Sự thay đổi sau trong file Global.asax làm việc cho tôi:

Cũ Mã số:

protected void Application_Start() 
    { 
     Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());    
     ... 
    } 

Mã mới:

protected void Application_Start() 
    { 
     Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
     Database.SetInitializer(new Initializer()); 
     ... 
    } 
0

Tôi vừa mới đi qua vấn đề này. Tôi đã xóa phần "connectionstrings" khỏi tệp Web.config và hiện tại ứng dụng đã bắt đầu chạy - không có phần kết nối! Tôi thêm phần trở lại, và cơ sở dữ liệu không phải là một lần nữa. Nó không phải là một giải pháp thích hợp, nhưng tôi chỉ cần thêm một điểm dữ liệu ở đây để những gì có khả năng có thể giải quyết vấn đề.

May mắn thay nó chỉ là một ứng dụng nhỏ "vứt bỏ" tôi sẽ hủy sớm ...

9

Đây là câu chuyện nhỏ buồn của tôi.

Thứ nhất, bài học kinh nghiệm:

  1. Phương pháp hạt giống sẽ không được gọi cho đến khi bối cảnh được sử dụng.
  2. Global.asax.cs sẽ không đạt điểm ngắt trong lần chạy đầu tiên bc nó chạy trước khi trình gỡ lỗi được đính kèm. Để đạt điểm ngắt trên Global.asax.cs, bạn có thể thêm một số khoảng trắng vào Web.config và nhấn một trang; sau đó nó sẽ bị đánh trúng.
  3. Nếu có kết nối VS đến db, quá trình tạo giống sẽ không xảy ra. Ứng dụng sẽ phát ra lỗi.

Vì vậy, để tránh những nỗi buồn:

  • Ngắt kết nối kết nối VS của bạn.
  • Chuyển lớp cơ sở DropCreateDatabaseAlways cho một lần.
  • Nhấn một trang sử dụng ngữ cảnh.

Bây giờ, nỗi buồn:

  1. Tôi có lớp Initializer tùy chỉnh của tôi trong tập tin Global.asax.cs của tôi. Tôi đã có một điểm break trên phương pháp Initializer Seed của tôi; Tôi bắt đầu ứng dụng và phương pháp không bao giờ bị trúng. :(
  2. tôi chỉ một điểm break trong cuộc gọi Database.SetInitializer tôi trong Application_Start. Đó là không bao giờ bị trúng. :(
  3. tôi nhận ra rằng tôi đã không có thay đổi schema db, như vậy thì tôi đã thay đổi DropCreateDatabaseIfModelChanges để DropCreateDatabaseAlways. Tuy nhiên, không có gì . :(
  4. Cuối cùng tôi đã đi đến một trang có sử dụng bối cảnh, và nó làm việc:./
+0

hoạt động này và cảm ơn thông tin hữu ích này. Tôi đóng kết nối cơ sở dữ liệu và sau đó chuyển cơ sở classto DropCreateDatabaseAlways. Nó hoạt động tốt. –

+0

Toàn cầu chỉ chạy lần đầu tiên. Vì vậy, đóng IISExpress. Đặt điểm ngắt của bạn ở chế độ toàn cầu và chạy. Nó sẽ nhấn nó, một lần, vì mức ứng dụng IIS của nó. – ppumkin

1

tôi cũng đã gặp khó khăn trong việc Seed() được gọi và tôi đánh giá cao tất cả những gợi ý hữu ích. ở trên và đã có một số may mắn bằng cách sử dụng DropCreateDatabaseAlways ... nhưng không LUÔN LUÔN !!

Gần đây nhất, tôi đã thêm dòng mã sau đây trong các nhà xây dựng của Repository của tôi để hiệu quả tốt:

public CatalogRepository() 
    { 
     _formCatalog.FormDescriptors.GetType(); 

    } 

Đó là đủ để kích hoạt các Seed() bị gọi. Nếu bạn đã thử mọi thứ ở trên câu trả lời này và vẫn không có may mắn, hãy thử. Chúc may mắn đây thực sự là một trải nghiệm tiêu tốn thời gian.

3

Bạn có thể gọi update-database để chạy thủ công phương thức giống bên trong lớp Configuration. Điều này cũng yêu cầu phải có enable-migrations.

PM> update-database 
Specify the '-Verbose' flag to view the SQL statements being applied to the target database. 
No pending code-based migrations. 
Running Seed method. 

internal sealed class Configuration : DbMigrationsConfiguration<ProjectManager.Data.Database.ProjectDb> 
{ 
    public Configuration() 
    { 
     AutomaticMigrationsEnabled = false; 
    } 

    protected override void Seed(ProjectManager.Data.Database.ProjectDb context) 
    { 
     context.Status.AddOrUpdate(
      new Status() { Id = 1, Text = "New" }, 
      new Status() { Id = 2, Text = "Working" }, 
      new Status() { Id = 3, Text = "Completed" }, 
      new Status() { Id = 4, Text = "Skipped" } 
     ); 
    } 
} 
0

cập nhật cần lưu ý rằng câu trả lời này là không chính xác! Lý do cho DB của tôi không nhận được hạt giống vẫn còn là một bí ẩn (nhưng nó không phải là thiếu một lời gọi constructor cơ bản mặc định, như được ghi nhận bởi @JaredReisinger)

Tôi đánh giá cao câu hỏi này là một chút cũ nhưng tôi đã kết thúc ở đây để người khác có thể. Đây là giá trị tuppence của tôi:

DB của tôi đã được tạo tốt nhưng không được gieo hạt, ngay cả khi tôi đã xóa cơ sở dữ liệu và bắt đầu lại bằng DropDatabaseInitialiser.

Sau khi đọc các mã trên tôi nhận thấy rằng constructor bối cảnh của tôi là này

public MyApp_Context() 
{ 
    // some code 
} 

trong khi ví dụ trên sẽ như sau cho các thiết lập của tôi

public MyApp_Context() : base("name=MyApp_Context") 
{ 
    // some code 
} 

Yup, tôi đã không gọi constructor của đối tượng cơ sở! Tôi sẽ không mong đợi mọi thứ ngoại trừ việc gieo hạt giống để làm việc trong trường hợp này nhưng dường như là trường hợp (lặp lại).

NB, tôi không thực sự cần cung cấp tên ngữ cảnh trong lời gọi hàm tạo cơ bản; Tôi chỉ viết nó theo cách ban đầu bởi vì tôi đã sao chép định dạng của giải pháp ở trên. Vì vậy, mã của tôi bây giờ là điều này, và hạt giống hoạt động trên cơ sở dữ liệu ban đầu tạo ra.

public MyApp_Context() : base() 
{ 
    // some code 
} 
+0

Hàm tạo mặc định của lớp cơ sở được tự động gọi bất kỳ lúc nào bạn không gọi một biến thể cụ thể của nó trực tiếp. Xem http://stackoverflow.com/questions/13166019/will-the-base-class-constructor-be-automatically-called để biết thêm chi tiết. – JaredReisinger

+0

Có, tôi sẽ phải đồng ý với bạn. Điều duy nhất là, khi tôi viết rằng ba năm trước, tôi dường như đã nhận thấy rằng bỏ qua (dư thừa) cơ sở() gọi dẫn đến một kết quả khác nhau hơn bao gồm nó. Tôi có thể khai thác mã đó vào một thời điểm nào đó, nhưng có lẽ là an toàn nhất để cho rằng có một số hiệu ứng khác có tác dụng ở đó. – Jon

0

Bảo đảm tỉ mỉ rằng bạn không khai báo biến ngữ cảnh nhiều lần. Nếu bạn tuyên bố lại sau khi gieo, hạt giống sẽ bị ghi đè.

0

Tôi đã gặp sự cố tương tự và sau khi thay đổi trong cả hai tệp Global.asaxIntializer tệp đã hoạt động. Tôi hy vọng nó sẽ làm việc cho những người vẫn còn gặp vấn đề về việc gieo giống dữ liệu.

Mã mới trong Global.asax:

protected void Application_Start() 
    { 
     Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
     Database.SetInitializer(new Initializer()); 
     ... 
    } 

mã cho tập tin Intializer:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context> 
Các vấn đề liên quan