2011-12-30 28 views
31

Tôi đang làm việc trên một dự án mà có thể kết thúc với nhiều phiên bản UI/biến thể, nhưng cho đến nay tôi đã có hai tiểu dự án trong giao diện Web có chứa Web của tôi với ASP.NET MVC . Dự án dịch vụ là nơi tôi có bối cảnh và mô hình cơ sở dữ liệu được xác định.Nơi để đặt Database.SetInitializer

Mục tiêu của tôi là có tối thiểu hoặc có thể không có tham chiếu đến mã cụ thể EF trong dự án Web của tôi. Tôi muốn nó được độc lập vì vậy khi tôi chuyển đổi các dll với backend dịch vụ (từ hãy nói SQL để XML hoặc MySQL) Tôi không nên thực hiện nhiều sửa đổi trong dự án MVC của tôi.

Đây là cách nó trông:

Project layout

Câu hỏi của tôi là: - cho đến nay tôi đã không tìm thấy ví dụ của việc sử dụng Database.SetInitializer ở vị trí khác ngoài Global.asax. Tôi muốn tạo lại cơ sở dữ liệu nếu mô hình đã thay đổi trong lớp DatabaseContextProvider giống như nhà máy của tôi hoặc trong lớp dịch vụ để lấy ra dữ liệu từ ngữ cảnh và cung cấp cho UI với DTO. Có bất kỳ khuyết điểm nào của địa điểm đó không? - Tôi muốn có connectionString của bối cảnh để có thể cấu hình được với tệp Thuộc tính/Cài đặt.settings - điều đó có hợp lý không?

Trả lời

14

Bạn cần có cơ chế để gọi phương thức Database.SetInitializer trước lần sử dụng đầu tiên của DbContext. Đó là lý do tại sao nó thường được gọi trong tập tin Global.asax.

Bạn có thể tạo một lớp học bằng phương pháp khởi tạo trong dự án tm.Service và gọi nó theo phương thức Application_Start và đặt Database.SetInitializer trong phương thức khởi tạo đó.

OK của nó để cung cấp chuỗi kết nối từ tệp cài đặt.

8

Tôi đặt nó trên trình tạo DbContext và hoạt động cho tôi.

public myDbContext() : base(connectionToDatabase) { 
     Database.SetInitializer<myDbContext>(null); 
    } 

Các giải pháp trên sẽ làm việc, nhưng nó không phải là hiệu quả như đoạn mã sau:

protected void Application_Start() 
    { 
     Database.SetInitializer<myDbContext>(null); 
    } 

Trong trường hợp của tôi, tôi không có một tài liệu tham khảo của Dal của tôi trên giao diện người dùng và cho rằng lý do tôi đã làm là tạo một cấu hình EntityFramework và đăng ký thiết lập của tôi bằng cách sử dụng sự phản chiếu.

protected void Application_Start() 
    {   
     EntityFrameworkConfig.RegisterSettings(); 
    } 


public static class EntityFrameworkConfig 
{ 
    public static void RegisterSettings() 
    { 
     // Use the file name to load the assembly into the current 
     // application domain. 
     Assembly a = Assembly.Load("MyAssembly"); 
     // Get the type to use. 
     Type myType = a.GetType("MyType"); 
     // Get the method to call. 
     MethodInfo myMethod = myType.GetMethod("MySettingsMethod"); 
     // Create an instance. 
     object obj = Activator.CreateInstance(MyType); 
     // Execute the method. 
     myMethod.Invoke(obj, null); 
    } 
} 

    public void Configurations() 
    { 
     //Other settings 
     Database.SetInitializer<myDbContext>(null); 
    } 

Cập nhật

Với Entity Framework 6, bây giờ bạn có thể sử dụng NullDatabaseInitializer

Database.SetInitializer(new NullDatabaseInitializer<MyDbContext>()); 
+6

Một vấn đề tiềm ẩn khi thực hiện việc này là nó có thể được gọi mỗi khi lớp myDbContext được xây dựng, điều này rất có thể là mỗi khi bạn sử dụng cơ sở dữ liệu. Tôi sẽ tưởng tượng đây là một hoạt động hợp lý tốn kém và bạn không muốn điều này xảy ra. Sử dụng Global.asax Application_Start hoặc một Trình xây dựng tĩnh trong lớp DataContext đảm bảo rằng mã chỉ được gọi một lần, khi ứng dụng được khởi động. – Holf

+0

Tôi đồng ý với Holf, mã nên được trên application_start –

32

Để tránh các khớp nối, tôi không muốn thiết lập khởi tạo bên ngoài hội có chứa DataContext. Vì vậy, tôi đã thêm một hàm tạo tĩnh cho DataContext. Bằng cách này, mọi dự án tham chiếu đến Assembly này sẽ được hưởng initializer mà không cần thiết lập nó một cách rõ ràng, và initializer được thiết lập chỉ một lần cho mỗi process.

static MyDataContext() 
{ 
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, Configuration>()); 
} 

Chuỗi kết nối tất nhiên sẽ được lấy từ tệp cấu hình ứng dụng.

+9

Không chắc chắn đây là một ý tưởng tốt bởi vì sau đó bạn có một khớp nối chặt chẽ giữa 'DbContext' và initializer. Chính sách khởi tạo phụ thuộc vào ngữ cảnh, ví dụ: cho các bài kiểm tra bạn sẽ sử dụng một 'DropCreateDatabaseAlways' và để tạo ra một' CreateDatabaseIfNotExists' ... – Pragmateek

3

Microsoft đã làm cho nó có thể, cho EF6 trở đi, để cấu hình một bộ khởi tạo cho mỗi bối cảnh cơ sở dữ liệu trong tệp cấu hình của ứng dụng. Xem phần cuối cùng trên trang Microsoft này: https://msdn.microsoft.com/en-us/data/jj556606.aspx

Điều này, như cách tiếp cận "Global.asax", có lợi thế, ví dụ: các dự án thử nghiệm đơn vị có thể sử dụng trình khởi tạo khác nhau cho cùng một bối cảnh cơ sở dữ liệu.

+0

Tôi tin rằng nó là một bộ khởi tạo cho mỗi ngữ cảnh, không phải cho mỗi cơ sở dữ liệu. Nhiều bối cảnh có thể hoạt động trên cùng một DB. –

+0

@DanielMackay Nhưng tôi _did_ viết "bối cảnh cơ sở dữ liệu" '! Bạn có perchance bỏ qua từ "bối cảnh" vì dòng bọc trực tiếp sau khi từ "cơ sở dữ liệu"? –

+1

họ không khuyên bạn nên cấu hình, thay vì họ nói rằng bạn có thể làm điều đó, cũng như làm điều đó trong mã. Đối với họ, bây giờ bạn có thể làm điều đó một trong hai cách. –

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