2012-02-02 12 views
21

Tôi đang cố gắng sử dụng di chuyển EF 4.3 với nhiều DbContexts mã đầu tiên. Ứng dụng của tôi được chia thành nhiều plugin, có thể có DbContext của riêng họ liên quan đến miền của họ. Ứng dụng nên sử dụng một cơ sở dữ liệu sql đơn.EF 4.3 Tự động di chuyển với nhiều DbContexts trong một cơ sở dữ liệu

Khi tôi cố gắng tự động di chuyển ngữ cảnh trong cơ sở dữ liệu trống, điều này chỉ thành công cho ngữ cảnh đầu tiên. Mọi ngữ cảnh khác cần có thuộc tính AutomaticMigrationDataLossAllowed-Property được đặt thành true nhưng sau đó cố gắng thả các bảng của bảng trước đó.

Vì vậy, câu hỏi của tôi là:

  • Làm thế nào tôi có thể nói sự di cư-cấu hình chỉ để chăm sóc các bảng được định nghĩa trong bối cảnh tương ứng của họ và để lại tất cả những người khác một mình?
  • Quy trình làm việc phù hợp để xử lý nhiều DbContexts với tự động di chuyển trong một cơ sở dữ liệu là gì?

Cảm ơn bạn!

+0

Đây là câu hỏi rất thú vị. Tôi tự hỏi nếu hỗ trợ nhiều bối cảnh là một phần của trường hợp sử dụng di chuyển. –

+2

Tôi rất nghi ngờ nhiều ngữ cảnh có thể hoạt động với tính năng di chuyển tự động, nó được thiết kế để cập nhật db để trông giống như ngữ cảnh không có vấn đề gì. Bạn có thể có nhiều may mắn hơn khi phát triển các plugin bằng cách sử dụng di chuyển thủ công, so với các cơ sở dữ liệu riêng biệt để tạo ra các di chuyển rồi áp dụng tất cả chúng cho cùng một db. – Betty

+0

Trong khi đó tôi nhìn vào các hội đồng EF 4.3, và tôi cũng nghi ngờ rằng khung di trú có thể đối phó với một số ngữ cảnh. Nhưng không có lý do kỹ thuật nào tôi có thể nghĩ đến. Với một mô hình EDM tại chỗ bạn có thể khác với cơ sở dữ liệu tìm thấy các bảng bảng hiện có tạo hoặc thay đổi và để lại kịch bản xóa bằng cách di chuyển thủ công cho người dùng. –

Trả lời

6

Mã di chuyển đầu tiên giả định rằng chỉ có một cấu hình di chuyển cho mỗi cơ sở dữ liệu (và một ngữ cảnh cho mỗi cấu hình).

tôi có thể nghĩ đến hai giải pháp khả thi:

  1. Tạo một bối cảnh tổng hợp bao gồm tất cả các thực thể của từng bối cảnh và tài liệu tham khảo này "siêu" bối cảnh từ lớp cấu hình di cư của bạn. Bằng cách này, tất cả các bảng sẽ được tạo ra trong cơ sở dữ liệu của người dùng, nhưng dữ liệu sẽ chỉ ở trong các bảng mà chúng đã cài đặt các plugin.

  2. Sử dụng cơ sở dữ liệu riêng cho từng ngữ cảnh. Nếu bạn có các thực thể được chia sẻ giữa các ngữ cảnh, hãy thêm di chuyển tùy chỉnh và thay thế cuộc gọi CreateTable(...) bằng lệnh gọi Sql("CREATE VIEW ...") để nhận dữ liệu từ cơ sở dữ liệu "có nguồn gốc" của tổ chức.

Tôi sẽ cố gắng # 1 vì nó giữ mọi thứ trong một cơ sở dữ liệu. Bạn có thể tạo một dự án riêng biệt trong giải pháp của bạn để chứa các di chuyển của bạn và ngữ cảnh "siêu" này. Chỉ cần thêm dự án, tham chiếu tất cả các dự án của plugin của bạn, tạo ngữ cảnh bao gồm tất cả các thực thể, sau đó gọi Enable-Migrations trên dự án mới này. Mọi thứ sẽ hoạt động như mong đợi sau đó.

+5

Tôi chấp nhận câu trả lời này, bất kể nó không thực sự là câu trả lời cho câu hỏi của tôi. Tôi nghĩ việc thiết kế di chuyển đến chỉ một ngữ cảnh cho mỗi cơ sở dữ liệu là một sai lầm. Một mặt, mỗi cơ sở dữ liệu kế thừa có các bảng không được sử dụng trong ngữ cảnh gây ra vấn đề. Mặt khác (ngay cả với chế độ xem được biên dịch trước) miền ứng dụng có ngữ cảnh với khoảng 100 thực thể khác nhau cần độ tuổi để bắt đầu. Vì vậy, chia nhỏ thành ngữ cảnh nhỏ hơn là giải pháp duy nhất cho đến nay. –

+3

Câu trả lời ban đầu của tôi đã trở thành một chút ngày. EF 6.0 đã loại bỏ giới hạn của một bối cảnh Code First cho mỗi cơ sở dữ liệu. Mọi thứ nên "chỉ hoạt động" trong các phiên bản 6.0 và mới hơn. – bricelam

3

Tôi có một trang web đang hoạt động với nhiều ngữ cảnh sử dụng di chuyển. Tuy nhiên, bạn cần phải sử dụng một cơ sở dữ liệu riêng biệt cho mỗi ngữ cảnh, và tất cả đều bị loại bỏ khỏi một lớp * Cấu hình trong không gian tên Migrations của dự án của bạn, ví dụ như CompanyDbContext trỏ tới Company.sdf bằng cách sử dụng CompanyConfiguration. update-database -configurationtypename CompanyConfiguration. Một điểm LogDbContext khác để Log.sdf sử dụng LogConfiguration, vv

Với công việc này, bạn đã thử tạo 2 bối cảnh trỏ vào cùng một cơ sở dữ liệu và yêu cầu trình mô hình hóa bỏ qua danh sách các bảng của bối cảnh khác?

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Ignore<OtherContextsClass>(); 
    // more of these 
} 

Vì di chuyển làm việc với Trình tạo mô hình, điều này có thể thực hiện công việc.

Thay thế crappy là tránh sử dụng Tự động di chuyển, tạo di chuyển mỗi lần và sau đó chọn lọc thủ công và xóa các câu không mong muốn, sau đó chạy chúng, mặc dù không có gì ngăn bạn tạo ra một công cụ đơn giản. báo cáo và sửa chữa di chuyển cho bạn.

+1

Cảm ơn bạn đã trả lời câu trả lời. Nhưng đáng tiếc là tôi không thể chia nhỏ cơ sở dữ liệu. Nhưng bạn đã cho tôi một gợi ý tốt để sử dụng đầu ra của automigrations như là một cơ sở cho những người thân. –

+0

bất kỳ ý tưởng nếu nó sẽ làm việc với nhiều lược đồ (ví dụ như dbo)? – Betty

32

Đây là những gì bạn có thể làm. rất đơn giản.

Bạn có thể tạo Lớp cấu hình cho từng ngữ cảnh của mình. ví dụ:

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
    public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

Bây giờ bạn thêm di chuyển. Bạn không cần phải kích hoạt di chuyển kể từ khi bạn đã làm với 2 phân loại ở trên.

Add-Migration -configuration Configuration1 Context1Init 

Điều này sẽ tạo tập lệnh di chuyển cho ngữ cảnh1. bạn có thể lặp lại điều này một lần nữa cho các Contexts khác.

Add-Migration -configuration Configuration2 Context2Init 

để cập nhật cơ sở dữ liệu của bạn

Update-Database -configuration Configuration1 
Update-Database -configuration Configuration2 

Điều này có thể được thực hiện theo thứ tự nào. Ngoại trừ bạn cần đảm bảo mỗi cấu hình được gọi theo thứ tự.

+0

Hoàn hảo, nó nói "Hãy chỉ định một để sử dụng" và tôi không biết làm thế nào để làm điều này. Cảm ơn! – joshcomley

+1

Tôi nhận được "mô hình ủng hộ bối cảnh đã thay đổi" khi tôi cố gắng sử dụng Context1 –

+2

my god này nên được đánh dấu là câu trả lời !!! cảm ơn bạn rất nhiều! Chỉ trong trường hợp tôi nhận được nó để làm việc với giải pháp này trên MVC 5 và EF 6 – oskar132

0

Tôi đã làm việc này với di chuyển thủ công, nhưng bạn không thể hạ cấp vì không thể phân biệt giữa các cấu hình trong bảng __MigrationHistory. Nếu tôi thử và hạ cấp thì nó sẽ xử lý việc di chuyển từ các cấu hình khác là tự động và vì tôi không cho phép mất dữ liệu, nó không thành công. Chúng tôi sẽ chỉ sử dụng nó để nâng cấp mặc dù vậy nó hoạt động cho các mục đích của chúng tôi.

Dường như nó có vẻ hơi uyên thâm, tôi chắc chắn sẽ không khó để hỗ trợ nó nếu không có sự chồng chéo giữa DbContexts.

1

Ok, tôi đã phải vật lộn với điều này trong một ngày bây giờ, và đây là giải pháp cho những người tìm kiếm câu trả lời ...

Tôi giả định rằng hầu hết mọi người đọc bài này ở đây vì họ có một DbContext lớn lớp học với rất nhiều DbSet <> tài sản và phải mất một thời gian dài để tải. Bạn có thể nghĩ đến chính mình, gee, có ý nghĩa, tôi nên chia nhỏ bối cảnh, vì tôi sẽ không sử dụng tất cả các dbsets cùng một lúc và tôi sẽ chỉ tải ngữ cảnh "một phần" dựa trên tình huống mà tôi cần nó. Vì vậy, bạn chia chúng ra, chỉ để tìm ra rằng Code First di cư không hỗ trợ cách suy nghĩ cách mạng của bạn. Vì vậy, bước đầu tiên của bạn phải được chia nhỏ các bối cảnh, sau đó bạn thêm lớp MigrationConfiguration cho mỗi ngữ cảnh mới, bạn đã thêm các chuỗi kết nối có tên chính xác giống như các lớp Ngữ cảnh mới của bạn.

Sau đó, bạn cố gắng chạy vừa chia tay bối cảnh từng người một, bằng cách thực hiện Add-Migration Context1 sau đó làm Cập nhật cơ sở dữ liệu--verbose ...

Tất cả mọi thứ dường như làm việc tốt, nhưng sau đó bạn nhận thấy rằng tất cả các tiếp theo Di chuyển đã xóa tất cả các bảng khỏi lần di chuyển Trước đó và chỉ để lại các bảng trong lần di chuyển cuối cùng.

Điều này là do, mô hình Di chuyển hiện tại dự kiến ​​Single DbContext trên mỗi Cơ sở dữ liệu và nó phải là kết quả phù hợp.

Những gì tôi cũng đã thử và ai đó đã đề xuất ở đây làm điều đó, là tạo một SuperContext duy nhất, có tất cả các bộ Db trong đó. Tạo một lớp Cấu hình di chuyển đơn lẻ và chạy lớp đó. Để lại các lớp ngữ cảnh một phần của bạn tại chỗ và cố gắng tạo nhanh và sử dụng chúng. EF phàn nàn rằng mô hình Sao lưu đã thay đổi. Một lần nữa, điều này là do EF so sánh dbcontext một phần của bạn với chữ ký bối cảnh All-Sets đã được bỏ qua từ việc di chuyển Siêu bối cảnh của bạn.

Đây là một lỗ hổng lớn trong quan điểm của tôi.

Trong trường hợp của tôi, tôi đã quyết định rằng PERFORMANCE quan trọng hơn di chuyển. Vì vậy, những gì tôi đã kết thúc làm, là sau khi tôi chạy trong bối cảnh siêu và có tất cả các bảng tại chỗ, tôi đã đi vào cơ sở dữ liệu và bảng _MigrationHistory xóa thủ công.

Bây giờ, tôi có thể khởi tạo và sử dụng các bối cảnh một phần mà không EF phàn nàn về điều đó. Nó không tìm thấy bảng MigrationHistory và chỉ di chuyển trên, cho phép tôi có một cái nhìn "một phần" của cơ sở dữ liệu.

Tất nhiên, giao dịch là bất kỳ thay đổi nào đối với mô hình sẽ phải được truyền theo cách thủ công đến cơ sở dữ liệu, vì vậy hãy cẩn thận.

Nó làm việc cho tôi mặc dù.

0

Chắc chắn giải pháp phải là sự sửa đổi của nhóm EntityFramework để thay đổi API để hỗ trợ sửa đổi trực tiếp bảng _MigrationHistory thành tên bảng bạn chọn như _MigrationHistory_Context1 sao cho nó có thể xử lý việc sửa đổi các thực thể DbContext độc lập. Bằng cách đó, tất cả chúng đều được xử lý riêng biệt và tùy thuộc vào nhà phát triển để đảm bảo rằng tên của các thực thể không xung đột.

Có vẻ như có rất nhiều người chia sẻ ý kiến ​​của tôi rằng một bản sao DbContext có tham chiếu đến phần siêu thực thể là một cách không thân thiện với doanh nghiệp để thực hiện mọi thứ. Duplicate DbContexts thất bại thảm hại cho các giải pháp dựa trên mô-đun (Prism hoặc tương tự).

1

Như đã đề cập ở trên bởi Brice, giải pháp thiết thực nhất là có 1 siêu DbContext cho mỗi ứng dụng/cơ sở dữ liệu.

Chỉ sử dụng 1 DbTiếp theo cho toàn bộ ứng dụng có vẻ là một nhược điểm kỹ thuật và phương pháp quan trọng, gây ảnh hưởng đến Modularity trong số những thứ khác. Ngoài ra, nếu bạn đang sử dụng dịch vụ dữ liệu WCF, bạn chỉ có thể sử dụng 1 DataService cho mỗi ứng dụng vì một DataService có thể ánh xạ tới chỉ 1 DbContext. Vì vậy, điều này làm thay đổi kiến ​​trúc đáng kể.

Mặt khác, một lợi thế nhỏ là tất cả mã di chuyển liên quan đến cơ sở dữ liệu đều được tập trung.

1

Tôi chỉ gặp vấn đề này và nhận ra lý do tôi chia chúng thành các ngữ cảnh khác nhau là hoàn toàn nhóm các mô hình liên quan trong các phần có thể quản lý và không vì bất kỳ lý do kỹ thuật nào khác. Thay vào đó, tôi đã khai báo ngữ cảnh của mình là một lớp một phần và bây giờ các tệp mã khác nhau với các mô hình khác nhau trong chúng có thể thêm DbSets vào DbContext.

Bằng cách này, ma thuật tự động vẫn hoạt động.

0

Tôi muốn mọi người biết rằng câu trả lời với điều này bên dưới là những gì hiệu quả đối với tôi nhưng với một cảnh báo trước: không sử dụng dòng MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
     public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

Tuy nhiên, tôi đã có 2 cơ sở dữ liệu thành lập với bối cảnh riêng của họ được xác định vì vậy tôi thấy mình nhận được một lỗi nói "YourProject.Models namespace đã có ContextNamespace1 định nghĩa".Điều này là do "MigrationsNamespace =" YourProject.Models.ContextNamespace2 ";" đã gây ra dbcontext được định nghĩa trong không gian tên YourProjects.Models hai lần sau khi tôi thử Init (một lần trong tệp Context1Init di chuyển và một khi tôi đã xác định nó trước đó).

Vì vậy, tôi phát hiện ra rằng những gì tôi phải làm vào thời điểm đó là bắt đầu cơ sở dữ liệu và di chuyển từ đầu (may mắn tôi không có dữ liệu tôi cần thiết để giữ) của tôi qua theo các hướng dẫn ở đây: http://pawel.sawicz.eu/entity-framework-reseting-migrations/

Sau đó, Tôi đã thay đổi mã để KHÔNG bao gồm dòng MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
     public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
    } 
} 

Sau đó, tôi chạy Add-Migration -Cấu hình Configuration1 Context1Init lệnh một lần nữa và Update-Cơ sở dữ liệu -Cấu hình Configuration1 dòng nữa (đối với bối cảnh thứ 2 của tôi quá), và cuối cùng, mọi thứ dường như được làm việc tuyệt vời ngay bây giờ.