Kho lưu trữ chung với EF 4.1 điểm là gì


145

Khi tôi tìm hiểu sâu hơn về DbContext, Dbset và các giao diện liên quan, tôi tự hỏi tại sao bạn cần triển khai một Kho lưu trữ "Chung" riêng biệt xung quanh các triển khai này?

Dường như DbContext và IDbset làm mọi thứ bạn cần và bao gồm "Đơn vị công việc" bên trong DbContext.

Tôi đang thiếu một cái gì đó ở đây hay có vẻ như mọi người thích thêm một lớp phụ thuộc mà không có lý do.


Đây là một vấn đề tranh chấp / dựa trên ý kiến. Tôi đã thảo luận về điều này ở đây .
Amit Joshi

Câu trả lời:


202

Bạn thực sự đúng. DbContextlà một triển khai của đơn vị mẫu công việc và IDbSetlà một triển khai của mẫu kho lưu trữ.

Các kho lưu trữ hiện đang rất phổ biến và sử dụng quá mức. Mọi người sử dụng chúng chỉ vì có hàng tá bài viết về việc tạo kho lưu trữ cho khung thực thể nhưng không ai thực sự mô tả các thách thức liên quan đến quyết định này.

Lý do chính để sử dụng kho lưu trữ thường là:

  • Ẩn EF từ lớp trên
  • Làm cho mã kiểm tra tốt hơn

Lý do đầu tiên là một số loại tinh khiết kiến ​​trúc và ý tưởng tuyệt vời rằng nếu bạn làm cho các lớp trên của bạn độc lập với EF, sau này bạn có thể chuyển sang khung kiên trì khác. Đã bao nhiêu lần bạn nhìn thấy những điều như vậy trong thế giới thực? Lý do này làm cho việc làm việc với EF trở nên khó khăn hơn nhiều vì kho lưu trữ của bạn phải phơi bày rất nhiều tính năng bổ sung bao bọc những gì mà EF cho phép theo mặc định.

Đồng thời gói mã EF có thể giữ cho mã của bạn được tổ chức tốt hơn và tuân theo quy tắc Tách rời mối quan tâm. Đối với tôi đây có thể là lợi thế thực sự duy nhất của kho lưu trữ và đơn vị công việc nhưng bạn phải hiểu rằng tuân theo quy tắc này với EF sẽ có thể giúp mã của bạn duy trì tốt hơn và dễ đọc hơn nhưng trong nỗ lực ban đầu để tạo ứng dụng của bạn sẽ cao hơn nhiều và Đối với các ứng dụng nhỏ hơn, điều này có thể phức tạp không cần thiết.

Lý do thứ hai là một phần chính xác. Nhược điểm lớn của EF là kiến ​​trúc cứng nhắc, khó có thể bị chế giễu, vì vậy nếu bạn muốn kiểm tra đơn vị lớp trên, bạn phải bọc bằng cách nào đó để cho phép thực hiện chế độ của nó. Nhưng điều này có nhiều hậu quả khác mà tôi đã mô tả ở đây .

Tôi theo dõi blog của Ayende . Nếu bạn đã từng sử dụng NHibernate có lẽ bạn biết bài viết của mình. Anh chàng này gần đây đã viết một số bài báo chống lại việc sử dụng kho lưu trữ với NHibernate nhưng NHibernate thì dễ bị nhạo báng hơn nhiều.


3
Bạn có thể giả định IDbSetbạn cũng có thể xác định giao diện tùy chỉnh trong ngữ cảnh xuất phát của mình nhưng đó là tất cả. Khi mã của bạn sử dụng ChangeTracker, Entries hoặc những thứ khác, nó sẽ đòi hỏi nỗ lực lớn để bao bọc tất cả.
Ladislav Mrnka

1
Có EF không phải là công cụ định hướng rất hiệu suất. Ít nhất MS có rất nhiều cơ hội để làm cho điều này tốt hơn trong các phiên bản trong tương lai.
Ladislav Mrnka

2
@chiccodoro: Phải rồi. Nhưng một khi lớp giả định của bạn hiển thị IQueryablehoặc chấp nhận Expression<>làm tham số được đặt bên trong cho truy vấn Linq-to-entity, bạn đang xác định logic bên ngoài thành phần bị giả với các tác dụng phụ không thể được kiểm tra bằng các bài kiểm tra đơn vị.
Ladislav Mrnka

8
Nếu tôi đang sử dụng DbSet và BdContext ngay trong lớp doanh nghiệp của mình, tôi phải tham khảo EntityFramework.dll ở đó cũng như trong dự án DataLayer của tôi. Điều đó một mình nói với tôi rằng nó cần một số loại bọc.
Ingó Vals

2
downvote: không đầy đủ - trừu tượng hóa EF đằng sau giao diện kho lưu trữ có thể làm cho cùng một mã máy khách chạy chính xác trong cả SL và WPF.
h.alex

21

Tôi đang vật lộn với các vấn đề tương tự, và khả năng thử nghiệm đơn vị của các lớp EF là rất quan trọng. Nhưng tôi đã xem qua bài viết tuyệt vời này giải thích cách thiết lập DbContext của EF 4.1 để có thể chế giễu bằng cách đảm bảo DbContext dẫn xuất của bạn triển khai giao diện chung và hiển thị IDbSet thay vì DbSet. Vì tôi đang sử dụng cách tiếp cận Cơ sở dữ liệu Đầu tiên, vì cơ sở dữ liệu của chúng tôi đã tồn tại, tôi chỉ cần sửa đổi các mẫu T4 được sử dụng để tạo DbContext dẫn xuất của mình để tạo ra nó để trả về các giao diện IDbset, cũng như xuất phát từ giao diện chung của tôi. Bằng cách đó, toàn bộ mọi thứ có thể dễ dàng bị chế giễu và bạn không cần phải triển khai mẫu Đơn vị công việc hoặc kho lưu trữ của riêng mình. Chỉ cần viết mã dịch vụ của bạn để sử dụng giao diện chung của bạn và khi bạn đi đến đơn vị kiểm tra nó,

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-reposeective/


5

Một lý do để tạo kho lưu trữ là vì vậy bạn có thể ẩn việc triển khai DBSet và DbContext nếu bạn quyết định chuyển từ EntityFramework sang một thứ khác hoặc ngược lại.

Ví dụ, tôi đang sử dụng NHibernate và tôi đã gói tất cả các cuộc gọi đến khung đó bên trong các lớp kho lưu trữ của mình. Họ trả lại IEnumerable cho họ được "chung chung" và kho của tôi có các hoạt động CRUD tiêu chuẩn (cập nhật, xóa, v.v.). Tôi đã chuyển sang Entity Framework từ lâu. Khi làm như vậy, tôi không cần thay đổi bất cứ điều gì trong các lớp ViewModel của mình hoặc xa hơn vì chúng chỉ vào kho lưu trữ của tôi - tôi chỉ cần thay đổi bên trong kho lưu trữ của mình. Điều này làm cho cuộc sống dễ dàng hơn nhiều khi di cư.

(Tôi đã sử dụng NHibernate vì chúng tôi đang kết nối với ISeries và tại thời điểm đó, không có việc triển khai chi phí nào bằng cách sử dụng EF với ISeries. Điều duy nhất có sẵn là trả 12.000 đô la cho IBM cho DB2Connect của họ)


"Hầu như" (về chủ đề ẩn DBSet và DbContext) bạn sẽ thấy rằng bạn không cần phải tiếp xúc với EF cho bất kỳ người tiêu dùng nào (ví dụ: nếu bạn tận dụng DI) nhưng bạn cần một giao diện hiển thị các thuộc tính <T> của IDbset hoặc tiến thêm một bước và thay vào đó hãy nhập tất cả các thuộc tính của bạn dưới dạng IQueryable <T>, nhưng quan điểm của tôi là bạn hoàn toàn có thể che giấu sự phụ thuộc của mình vào DbSet và DbContext. Các op CRUD sau đó có thể được viết dưới dạng các phương thức mở rộng, bạn có thể viết nhiều phương thức mở rộng cho các cửa hàng sao lưu khác nhau. Tuy nhiên, bạn sẽ không che giấu việc sử dụng LINQ.
Shaun Wilson
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.