Khung thực thể và nhóm kết nối


268

Gần đây tôi đã bắt đầu sử dụng Entity Framework 4.0 trong ứng dụng .NET 4.0 của mình và tò mò về một vài điều liên quan đến việc gộp chung.

  1. Nhóm kết nối mà tôi biết được quản lý bởi nhà cung cấp dữ liệu ADO.NET, trong trường hợp của tôi là máy chủ MS SQL. Điều này có áp dụng khi bạn khởi tạo một bối cảnh thực thể mới ( ObjectContext), tức là new MyDatabaseModelEntities()không tham số không?

  2. Những lợi thế và bất lợi của a) tạo bối cảnh thực thể toàn cầu cho ứng dụng (tức là một thể hiện tĩnh) hoặc b) tạo và hiển thị bối cảnh thực thể cho mỗi hoạt động / phương thức đã cho, với một usingkhối.

  3. Bất kỳ đề xuất nào khác, thực tiễn tốt nhất hoặc phương pháp tiếp cận phổ biến cho các kịch bản nhất định mà tôi nên biết về?

Câu trả lời:


369
  1. Nhóm kết nối được xử lý như trong bất kỳ ứng dụng ADO.NET nào khác. Kết nối thực thể vẫn sử dụng kết nối cơ sở dữ liệu truyền thống với chuỗi kết nối truyền thống. Tôi tin rằng bạn có thể tắt kết nối kết nối trong chuỗi kết nối nếu bạn không muốn sử dụng nó. (đọc thêm về Nhóm kết nối máy chủ SQL (ADO.NET) )
  2. Không bao giờ sử dụng bối cảnh toàn cầu. ObjectContext bên trong thực hiện một số mẫu bao gồm Bản đồ nhận dạng và Đơn vị công việc. Tác động của việc sử dụng bối cảnh toàn cầu là khác nhau cho mỗi loại ứng dụng.
  3. Đối với các ứng dụng web sử dụng bối cảnh duy nhất cho mỗi yêu cầu. Đối với các dịch vụ web sử dụng bối cảnh duy nhất cho mỗi cuộc gọi. Trong ứng dụng WinForms hoặc WPF sử dụng ngữ cảnh đơn cho mỗi biểu mẫu hoặc mỗi người trình bày. Có thể có một số yêu cầu đặc biệt sẽ không cho phép sử dụng phương pháp này nhưng trong hầu hết tình huống này là đủ.

Nếu bạn muốn biết tác động nào có bối cảnh đối tượng đơn cho ứng dụng WPF / WinForm, hãy kiểm tra bài viết này . Đó là về NHibernate session nhưng ý tưởng là như nhau.

Biên tập:

Khi bạn sử dụng EF, theo mặc định, nó chỉ tải mỗi thực thể một lần cho mỗi ngữ cảnh. Truy vấn đầu tiên tạo ra instace thực thể và lưu trữ nó bên trong. Bất kỳ truy vấn tiếp theo nào yêu cầu thực thể có cùng khóa đều trả về thể hiện được lưu trữ này. Nếu các giá trị trong kho dữ liệu thay đổi, bạn vẫn nhận được thực thể với các giá trị từ truy vấn ban đầu. Đây được gọi là mẫu bản đồ nhận dạng . Bạn có thể buộc bối cảnh đối tượng tải lại thực thể nhưng nó sẽ tải lại một thể hiện được chia sẻ.

Mọi thay đổi được thực hiện cho thực thể sẽ không được duy trì cho đến khi bạn gọi SaveChangesvào ngữ cảnh. Bạn có thể thay đổi trong nhiều thực thể và lưu trữ chúng cùng một lúc. Đây được gọi là mẫu Đơn vị công việc . Bạn không thể chọn lọc nói thực thể đính kèm nào bạn muốn lưu.

Kết hợp hai mẫu này và bạn sẽ thấy một số hiệu ứng thú vị. Bạn chỉ có một phiên bản thực thể cho toàn bộ ứng dụng. Mọi thay đổi đối với thực thể đều ảnh hưởng đến toàn bộ ứng dụng ngay cả khi những thay đổi chưa được duy trì (cam kết). Trong hầu hết các lần, đây không phải là điều bạn muốn. Giả sử rằng bạn có một hình thức chỉnh sửa trong ứng dụng WPF. Bạn đang làm việc với thực thể và bạn quyết định hủy bỏ chỉnh sửa phức tạp (thay đổi giá trị, thêm thực thể liên quan, xóa các thực thể liên quan khác, v.v.). Nhưng thực thể đã được sửa đổi trong bối cảnh chia sẻ. Bạn sẽ làm gì? Gợi ý: Tôi không biết về bất kỳ Hủy nào hoặc Hoàn tác trên ObjectContext.

Tôi nghĩ rằng chúng ta không phải thảo luận về kịch bản máy chủ. Chỉ cần chia sẻ một thực thể giữa nhiều yêu cầu HTTP hoặc các cuộc gọi dịch vụ Web sẽ khiến ứng dụng của bạn trở nên vô dụng. Bất kỳ yêu cầu nào cũng có thể kích hoạt SaveChangesvà lưu một phần dữ liệu từ một yêu cầu khác vì bạn đang chia sẻ một đơn vị công việc giữa tất cả chúng. Điều này cũng sẽ có một vấn đề khác - bối cảnh và mọi thao tác với các thực thể trong ngữ cảnh hoặc kết nối cơ sở dữ liệu được sử dụng bởi bối cảnh không phải là luồng an toàn.

Ngay cả đối với một ứng dụng chỉ đọc, bối cảnh toàn cầu không phải là một lựa chọn tốt bởi vì bạn có thể muốn có dữ liệu mới mỗi khi bạn truy vấn ứng dụng.


Cảm ơn vì đã trả lời. Có lẽ bạn có thể giải thích lý do tại sao nó là xấu khi sử dụng một bối cảnh toàn cầu duy nhất? Nó làm cho truy cập song song khó hơn, chắc chắn, nhưng những gì khác ...?
Noldorin

Ok, bây giờ rõ ràng hơn nhiều, cảm ơn bạn. Chỉ cần xác nhận, mặc dù bối cảnh toàn cầu không bao giờ thực sự phù hợp, một bối cảnh duy nhất cho "hộp thoại chỉnh sửa" hoặc như vậy có thể là cách đúng đắn? Trong các tình huống khác, như các dịch vụ web và ASP.NET, bối cảnh trong các phương thức chỉ có ý nghĩa hơn. Về chính xác?
Noldorin

Tôi lấy lời khuyên của bạn và loại bỏ singelton. Bây giờ tôi nhận được một lỗi khác: stackoverflow.com/questions/14795899/
Kẻ

Tôi hiểu rằng việc triển khai Đơn vị mẫu công việc và đóng gói DbContext sẽ tách biệt hoạt động logic và cơ sở dữ liệu nghiệp vụ. Tôi không thể hiểu cách triển khai Đơn vị mẫu công việc và chỉ sử dụng TransactionScope cho một số thao tác.
Rudolf Dvoracek

4
@RudolfDvoracek: Dễ dàng. TransactionScopekhông thuộc về đơn vị công việc, nó thuộc về logic kinh doanh của bạn vì chính logic đó xác định giao dịch. Đơn vị công việc chỉ xác định những gì cần được duy trì cùng nhau trong khi phạm vi giao dịch cho phép bạn sử dụng đơn vị công việc kiên trì nhiều lần trong cùng một giao dịch.
Ladislav Mrnka

70

Theo Daniel Simmons:

Tạo một cá thể ObjectContext mới trong câu lệnh Sử dụng cho mỗi phương thức dịch vụ để nó được xử lý trước khi phương thức trả về. Bước này là rất quan trọng cho khả năng mở rộng dịch vụ của bạn. Nó đảm bảo rằng các kết nối cơ sở dữ liệu không được giữ mở trong các cuộc gọi dịch vụ và trạng thái tạm thời được sử dụng bởi một hoạt động cụ thể là rác được thu thập khi hoạt động đó kết thúc. Entity Framework tự động lưu trữ siêu dữ liệu và thông tin khác mà nó cần trong miền ứng dụng và ADO.NET kết nối cơ sở dữ liệu, do đó, việc tạo lại bối cảnh mỗi lần là một thao tác nhanh chóng.

Đây là từ bài viết toàn diện của mình ở đây:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

Tôi tin rằng lời khuyên này mở rộng cho các yêu cầu HTTP, vì vậy sẽ hợp lệ cho ASP.NET. Một ứng dụng khách hàng thân thiện, mập mạp như ứng dụng WPF có thể là trường hợp duy nhất cho bối cảnh "chia sẻ".


Cảm ơn, đó là một trích dẫn rất nhiều thông tin ở đó. Tuy nhiên, tôi vẫn tự hỏi liệu bối cảnh chung (toàn cầu) sẽ được chiếm dụng ngay cả đối với ứng dụng WPF của khách hàng hay không. Có bất kỳ lợi thế ngay cả trong trường hợp này?
Noldorin

Sẽ không có lợi thế cho bối cảnh toàn cầu trong một ứng dụng WPF, nhưng có lẽ cũng sẽ không có bất lợi nào. Nếu bạn thực hiện bối cảnh toàn cầu, bạn có thể phải thực hiện một số quản lý thủ công các kết nối cơ sở dữ liệu (đóng kết nối rõ ràng) trong trường hợp tỷ lệ yêu cầu cao.
Dave Swersky

1
Đúng; Vì vậy, về cơ bản tôi không bao giờ có thể thực sự sai bằng cách sử dụng nhiều bối cảnh tạm thời (cho tôi biết kết nối đang xảy ra)? ... Nếu bạn đang sử dụng một bối cảnh toàn cầu duy nhất, không thể kết nối trong lý thuyết giảm xuống tại một thời điểm ngẫu nhiên?
Noldorin

1
@Nolodrin: Tôi không nghĩ kết nối sẽ giảm "ngẫu nhiên" ... rủi ro là các kết nối có thể bị mở quá lâu và bão hòa nhóm kết nối.
Dave Swersky

1
IDisposableDo đó, triển khai ObjectContext / DbContext nên được mở trong thời gian hợp lý ngắn nhất, là quan điểm của tôi.
nicodemus13

12

Theo tài liệu của EF6 (4,5 cũng): https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 Bối cảnh theo yêu cầu

Các bối cảnh của Entity Framework có nghĩa là được sử dụng như các trường hợp tồn tại trong thời gian ngắn để cung cấp trải nghiệm hiệu suất tối ưu nhất . Các bối cảnh dự kiến ​​sẽ tồn tại trong thời gian ngắn và bị loại bỏ, và như vậy đã được triển khai để rất nhẹ và tái sử dụng siêu dữ liệu bất cứ khi nào có thể. Trong các kịch bản web, điều quan trọng là phải ghi nhớ điều này và không có bối cảnh nhiều hơn thời lượng của một yêu cầu. Tương tự, trong các tình huống không phải là web, ngữ cảnh nên được loại bỏ dựa trên sự hiểu biết của bạn về các mức bộ nhớ đệm khác nhau trong Khung thực thể. Nói chung, người ta nên tránh có một phiên bản ngữ cảnh trong suốt vòng đời của ứng dụng, cũng như bối cảnh trên mỗi luồng và bối cảnh tĩnh.


2
Tôi biết câu trả lời này đã ở đây được một thời gian, nhưng tôi phải nói rằng điều này đã giúp tôi đỡ đau đầu. Giữ lỗi "Pooled Connection" khi sử dụng EF với Oracle và không thể hiểu tại sao. Tôi đã thiết lập dbContext thành một biến lớp, khởi tạo nó khi tạo. Thay đổi nó để tạo bối cảnh khi cần thiết đã sửa chữa tất cả các bệnh tật trong thế giới của tôi. Cảm ơn bạn!
Fletchius

1

Mã dưới đây đã giúp đối tượng của tôi được làm mới với các giá trị cơ sở dữ liệu mới. Lệnh Entry (object) .Reload () buộc đối tượng gọi lại các giá trị cơ sở dữ liệu

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();

cũng như điều này cho các bộ sưu tập (mã VB):CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)
Biệt thự Ivan Ferrer
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.