Để lưu trữ hoặc không lưu trữ


10

Khi tôi lần đầu tiên biết về Thiết kế hướng miền, tôi cũng được giới thiệu về kho lưu trữ và đơn vị các mẫu công việc dường như là đỉnh cao đối với những đứa trẻ tuyệt vời đã ném các truy vấn SQL như cavemans vào cơ sở dữ liệu. Càng đi sâu vào chủ đề đó, tôi càng biết rằng chúng dường như không còn cần thiết nữa vì các ORM như EFNHibernate triển khai cả đơn vị công việc và kho lưu trữ vào một API, được gọi là phiên hoặc ngữ cảnh.

Bây giờ tôi không chắc phải làm gì. Để lưu trữ hoặc không lưu trữ. Tôi thực sự hiểu lập luận rằng sự trừu tượng bị rò rỉ như vậy chỉ làm phức tạp hóa mọi thứ trong khi thêm hoàn toàn không có gì có thể đơn giản hóa việc truy cập dữ liệu, tuy nhiên, không cảm thấy đúng khi kết hợp mọi khía cạnh có thể có trong ứng dụng của tôi với ví dụ Entity Framework . Thông thường, tôi làm theo một vài hướng dẫn đơn giản:

  1. Lớp miền là trái tim của hệ thống, chứa các thực thể, dịch vụ, kho lưu trữ ...
  2. Tầng cơ sở hạ tầng cung cấp việc triển khai các giao diện miền của mối quan tâm về cơ sở hạ tầng, ví dụ: tệp, cơ sở dữ liệu, giao thức ..
  3. Lớp ứng dụng lưu trữ một gốc thành phần kết nối mọi thứ và sắp xếp mọi thứ.

Các giải pháp của tôi thường trông như thế này:

Domain.Module1
Domain.Module2
    IModule2Repo
    IModule2Service
    Module2
Infrastructure.Persistence
    Repositories
        EntityFrameworkRepositoryBase
MyApp
    Boostrapper
        -> inject EntityFrameworkRepositoryBase into IRepository etc.

Tôi giữ sạch lớp miền của mình bằng cách sử dụng lớp IRepository<'T>cũng là một mối quan tâm tên miền không phụ thuộc vào bất cứ điều gì khác cho tôi biết cách truy cập dữ liệu. Khi bây giờ tôi sẽ thực hiện cụ thể IModule2Serviceyêu cầu truy cập dữ liệu, tôi sẽ phải tiêm DbContextvà bằng cách này, ghép nó trực tiếp với lớp cơ sở hạ tầng. ( Đến với dự án Visual Studio, điều này có thể thực sự khó khăn vì phụ thuộc vòng tròn! )

Ngoài ra, cái gì có thể thay thế cho khocông việc chết tiệt ? CQRS? Làm thế nào để trừu tượng một khung cơ sở hạ tầng thuần túy?


1
Bên cạnh đó, nếu bạn đang nói về 'Kho lưu trữ' như được mô tả trong DDD, thì EF và nHibernate không phải là kho lưu trữ. Chắc chắn, họ trừu tượng một phần cơ chế truy cập dữ liệu, nhưng có nhiều hơn một kho lưu trữ hơn thế .
Eric King

Câu trả lời:


4

Kỹ thuật là tất cả về thỏa hiệp. Và phát triển phần mềm cũng vậy. Ngay bây giờ, tôi tin rằng chỉ có tùy chọn khác, sẽ đơn giản hơn, là làm việc trực tiếp với ORM. Nhưng như bạn đã nói, điều đó có thể khóa bạn vào khuôn khổ kiên trì cụ thể.

Vì vậy, bạn phải tự hỏi mình "Sự phức tạp bổ sung có đáng để tách mã của bạn khỏi sự kiên trì không". Mỗi lần tôi nghe mọi người nói rằng họ muốn tách mã của họ khỏi sự kiên trì, tôi hỏi "Đã bao nhiêu lần trong sự nghiệp, bạn thay đổi khuôn khổ kiên trì của mình?"

Các vấn đề tôi thấy với các kho lưu trữ là chúng làm cho những thay đổi chung trở nên khó khăn hơn. Ví dụ. thêm cách mới để truy vấn tổng hợp. Và họ làm cho những thay đổi không phổ biến (được cho là) ​​dễ dàng hơn. Ví dụ. thay đổi thực hiện các kho lưu trữ.

Sau đó, còn có đối số kiểm thử đơn vị, theo đó tôi nói "Nếu khung kiên trì không cho phép bạn giả định cơ sở dữ liệu, trong bộ nhớ hoặc cục bộ, thì nó hoàn toàn không đáng để sử dụng khung."


1
Quan điểm của kho lưu trữ là tách ứng dụng khỏi sự bền bỉ và không có sự phức tạp nào liên quan. Và tôi thay đổi các chi tiết liên tục ít nhất một lần, bởi vì quyền truy cập db là điều cuối cùng tôi mã hóa, cho đến thời điểm đó tôi đang sử dụng trong repos bộ nhớ. Bên cạnh đó, có một cái bẫy rất tinh tế khi bạn đang sử dụng một chi tiết bền bỉ trực tiếp. Các đối tượng kinh doanh của bạn sẽ có xu hướng được thiết kế để tương thích với nó, thay vì bất khả tri. Và đó là bởi vì một thực thể được đóng gói đúng cách, phong phú không thể được phục hồi trực tiếp từ bất kỳ bộ lưu trữ nào (ngoại trừ bộ nhớ) mà không có (một số cách giải quyết xấu xí)
MikeSW

Về việc thêm một cách mới để truy vấn một gốc tổng hợp hoặc bất kỳ thực thể nào, đó là lý do tại sao CQRS xuất hiện. Cá nhân, tôi giữ Kho lưu trữ cho mục đích tên miền và sử dụng trình xử lý truy vấn để truy vấn thực tế. Và những trình xử lý này được kết hợp rất chặt chẽ với db và ofc rất hiệu quả với những gì họ làm.
MikeSW

3

Tôi là pro-repository, mặc dù tôi đã chuyển khỏi các mẫu kho lưu trữ chung. Thay vào đó, tôi sắp xếp các kho lưu trữ của mình với chức năng kinh doanh mà chúng phục vụ. Các kho lưu trữ không nhằm mục đích trừu tượng hóa ORM, vì đây không phải là bất cứ điều gì tôi mong muốn thay đổi, đồng thời tôi tránh làm cho một kho lưu trữ quá chi tiết. (Tức là CRUD) Thay vào đó, kho của tôi phục vụ hai đến ba mục đích chính:

  • Phục hồi dữ liệu
  • Tạo dữ liệu
  • Xóa cứng

Để lấy dữ liệu, kho lưu trữ luôn trả về IQueryable<TEntity>. Để tạo dữ liệu, nó trả về TEntity. Kho lưu trữ xử lý bộ lọc cấp cơ sở của tôi, chẳng hạn như trạng thái "hoạt động" ủy quyền cho các hệ thống sử dụng các mẫu xóa mềm và trạng thái "hiện tại" cho các hệ thống sử dụng dữ liệu lịch sử. Việc tạo dữ liệu chỉ chịu trách nhiệm đảm bảo rằng các tham chiếu cần thiết được giải quyết và liên kết và thực thể được thiết lập và sẵn sàng hoạt động.

Cập nhật dữ liệu là trách nhiệm của logic nghiệp vụ làm việc với (các) thực thể được đề cập. Điều này có thể bao gồm những thứ như quy tắc xác nhận. Tôi không thử đóng gói nó trong một phương thức lưu trữ.

Xóa trong hầu hết các hệ thống của tôi là xóa mềm để nó được cập nhật dữ liệu. (IsActive = false) Trong trường hợp xóa cứng, đây sẽ là một lớp lót trong Kho lưu trữ.

Tại sao phải lưu trữ? Khả năng kiểm tra. Chắc chắn, DbContext có thể bị chế giễu, nhưng đơn giản hơn là giả định một lớp trả vềIQueryable<TEntity>. Chúng cũng chơi tốt với mẫu UoW, cá nhân tôi sử dụng mẫu DbContextScope của Mehdime để tìm ra đơn vị công việc ở mức tôi muốn (Bộ điều khiển Ie trong MVC) và cho phép các bộ điều khiển và lớp dịch vụ trợ giúp của tôi sử dụng kho lưu trữ mà không cần phải chuyển tham chiếu đến UoW / dbContext xung quanh. Sử dụng IQueryable có nghĩa là bạn không cần nhiều phương thức trình bao bọc trong kho lưu trữ và mã của bạn có thể tối ưu hóa cách dữ liệu sẽ được tiêu thụ. Ví dụ, kho lưu trữ không cần hiển thị các phương thức như "Tồn tại" hoặc "Đếm" hoặc cố gắng bọc các thực thể với các POCO khác trong trường hợp bạn muốn có các bộ dữ liệu phụ. Họ thậm chí không cần xử lý các tùy chọn tải háo hức cho dữ liệu liên quan mà bạn có thể cần hoặc không cần. Bằng cách chuyển IQueryable, mã gọi có thể:

.Any()
.Count()
.Include() // Generally avoided, instead I use .Select()
.Where()
.Select(x => new ViewModel or Anon. Type)
.Skip().Take()
.FirstOrDefault() / .SingleOrDefault() / .ToList()

Rất linh hoạt và từ một PoV thử nghiệm, kho lưu trữ giả của tôi chỉ cần trả về Danh sách các đối tượng thực thể được điền.

Đối với các kho lưu trữ chung, phần lớn tôi đã chuyển khỏi các kho này bởi vì khi bạn kết thúc với một kho lưu trữ trên mỗi bảng, bộ điều khiển / dịch vụ của bạn kết thúc với các tham chiếu đến một số kho lưu trữ để thực hiện một hành động kinh doanh. Trong hầu hết các trường hợp, chỉ có một hoặc hai trong số các kho lưu trữ này thực sự đang thực hiện các thao tác ghi (với điều kiện bạn đang sử dụng các thuộc tính điều hướng đúng cách) trong khi phần còn lại hỗ trợ những người có Đọc. Tôi muốn có một cái gì đó giống như một Kho lưu trữ đơn hàng có khả năng đọc và tạo đơn hàng và đọc bất kỳ tra cứu có liên quan, v.v. (đối tượng khách hàng nhẹ, sản phẩm, v.v.) để tham khảo khi tạo đơn hàng, hơn là nhấn 5 hoặc 6 kho khác nhau. Nó có thể vi phạm những người theo chủ nghĩa thuần túy DNRY, nhưng lập luận của tôi cho rằng mục đích của kho lưu trữ là phục vụ việc tạo Đơn hàng bao gồm các tham chiếu liên quan.Repository<Product>để có được các sản phẩm trong cơ sở của một đơn đặt hàng, tôi chỉ cần một thực thể với một số ít các lĩnh vực. Đơn hàng của tôi có thể có một .GetProducts()phương thức trả về IQueryable<ProductSummary>mà tôi thấy đẹp hơn phương thức Repository<Product>mà cuối cùng có một số phương thức "Nhận" để thử và phục vụ các khu vực khác nhau của nhu cầu của ứng dụng và / hoặc một số biểu thức lọc thông qua phức tạp.

Tôi chọn mã đơn giản hơn để dễ theo dõi, kiểm tra và điều chỉnh. Nó có thể bị lạm dụng theo những cách xấu, nhưng tôi muốn có một cái gì đó mà sự lạm dụng dễ dàng phát hiện và sửa chữa hơn là cố gắng "khóa" mã theo cách không thể bị lạm dụng, thất bại, và sau đó có một cái gì đó một cơn ác mộng để thực sự làm những gì khách hàng trả tiền để có được nó cuối cùng. :)

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.