Các dịch vụ nên luôn trả về DTO, hay chúng cũng có thể trả về các mô hình miền?


174

Tôi (đang) thiết kế ứng dụng quy mô lớn, chúng tôi sử dụng kiến ​​trúc nhiều lớp dựa trên DDD.

Chúng tôi có MVC với lớp dữ liệu (triển khai kho lưu trữ), lớp miền (định nghĩa mô hình và giao diện miền - kho lưu trữ, dịch vụ, đơn vị công việc), lớp dịch vụ (triển khai dịch vụ). Cho đến nay, chúng tôi sử dụng các mô hình miền (chủ yếu là các thực thể) trên tất cả các lớp và chúng tôi chỉ sử dụng các DTO làm mô hình khung nhìn (trong bộ điều khiển, dịch vụ trả về (các) mô hình miền và bộ điều khiển tạo mô hình khung nhìn, được chuyển đến dạng xem).

Tôi đã đọc vô số bài viết về việc sử dụng, không sử dụng, lập bản đồ và chuyển DTO. Tôi hiểu rằng không có bất kỳ câu trả lời dứt khoát nào, nhưng tôi không chắc liệu nó có ổn hay không trả lại các mô hình miền từ các dịch vụ cho bộ điều khiển. Nếu tôi trả về mô hình miền, nó vẫn không bao giờ được chuyển đến dạng xem, vì bộ điều khiển luôn tạo mô hình khung nhìn cụ thể cho chế độ xem - trong trường hợp này, nó có vẻ hợp pháp. Mặt khác, nó không cảm thấy đúng khi mô hình miền rời khỏi lớp nghiệp vụ (lớp dịch vụ). Đôi khi dịch vụ cần trả về đối tượng dữ liệu không được xác định trong miền và sau đó chúng tôi phải thêm đối tượng mới vào miền không được ánh xạ hoặc tạo đối tượng POCO (điều này thật xấu, vì một số dịch vụ trả về mô hình miền, một số dịch vụ trả lại hiệu quả DTOs).

Câu hỏi đặt ra là - nếu chúng ta sử dụng nghiêm ngặt các mô hình xem, liệu có thể trả lại các mô hình miền hoàn toàn cho bộ điều khiển hay chúng ta nên luôn sử dụng DTO để liên lạc với lớp dịch vụ? Nếu vậy, điều chỉnh các mô hình miền dựa trên những dịch vụ nào cần? (Thành thật mà nói tôi không nghĩ vậy, vì các dịch vụ nên tiêu thụ tên miền nào.) Nếu chúng ta nên tuân thủ nghiêm ngặt các DTO, chúng có nên được định nghĩa trong lớp dịch vụ không? (Tôi cũng nghĩ vậy) s) - có vẻ như sẽ không có ý nghĩa gì khi tạo DTO giống như mô hình miền) - nhưng tôi thích sự nhất quán và thực hành tốt.

Bài viết Miền vs DTO vs ViewModel - Cách sử dụng và khi nào? (và một số bài viết khác) rất giống với vấn đề của tôi, nhưng nó không trả lời (các) câu hỏi này. Bài viết Tôi có nên triển khai DTO trong mẫu kho lưu trữ với EF không? cũng tương tự, nhưng nó không đối phó với DDD.

Tuyên bố miễn trừ trách nhiệm: Tôi không có ý định sử dụng bất kỳ mẫu thiết kế nào chỉ vì nó tồn tại và lạ mắt, mặt khác, tôi cũng muốn sử dụng các mẫu và thực tiễn thiết kế tốt vì nó giúp thiết kế toàn bộ ứng dụng, giúp phân tách mối quan tâm, thậm chí tohugh sử dụng mẫu cụ thể không phải là "cần thiết", ít nhất là tại thời điểm này.

Như mọi khi, cảm ơn bạn.


28
Đối với những người bỏ phiếu cho gần - xin vui lòng giải thích lý do tại sao bạn muốn đóng câu hỏi này như ý kiến?
Robert Goldwein

20
@Aron "Đánh giá mã là trang web câu hỏi và trả lời để chia sẻ mã từ các dự án bạn đang thực hiện để đánh giá ngang hàng." - câu hỏi của tôi hoàn toàn không phải về mã, vì vậy nó sẽ lạc đề ở đó; SO: "Tập trung vào các câu hỏi về một vấn đề thực tế mà bạn đã gặp phải. Bao gồm các chi tiết về những gì bạn đã cố gắng và chính xác những gì bạn đang cố gắng làm." - Tôi có vấn đề chuyên gia cụ thể, mà tôi đã cố gắng giải quyết. Bạn có thể vui lòng nói cụ thể hơn những gì sai với câu hỏi này không, vì nhiều câu hỏi ở đây là về kiến ​​trúc và những câu hỏi như vậy rõ ràng là ổn, vì vậy tôi có thể tránh bất kỳ hiểu lầm nào nữa không?
Robert Goldwein

7
Cảm ơn bạn đã hỏi câu hỏi đó. Bạn đã làm một ân huệ cho tôi, và làm cho cuộc sống của tôi đơn giản và hạnh phúc hơn nhiều, cảm ơn bạn.
Loa

9
@RobertGoldwein, đừng bận tâm đến SO Close Mafia, câu hỏi của bạn là hợp pháp.
hyankov

3
Cảm ơn rất nhiều vì đã hỏi câu hỏi này
salman

Câu trả lời:


177

không cảm thấy đúng khi mô hình miền rời khỏi lớp nghiệp vụ (lớp dịch vụ)

Làm cho bạn cảm thấy như bạn đang rút ruột ra phải không? Theo Martin Fowler: Tầng dịch vụ xác định ràng buộc của ứng dụng, nó đóng gói tên miền. Nói cách khác, nó bảo vệ tên miền.

Đôi khi dịch vụ cần trả về đối tượng dữ liệu không được xác định trong miền

Bạn có thể cung cấp một ví dụ về đối tượng dữ liệu này?

Nếu chúng ta nên tuân thủ nghiêm ngặt các DTO, chúng có nên được định nghĩa trong lớp dịch vụ không?

Có, bởi vì phản hồi là một phần của lớp dịch vụ của bạn. Nếu nó được định nghĩa "ở một nơi khác" thì lớp dịch vụ cần tham chiếu đến "nơi khác", thêm một lớp mới vào lasagna của bạn.

Bạn có thể trả lại các mô hình miền hoàn toàn cho bộ điều khiển hay chúng ta nên luôn sử dụng DTO để liên lạc với lớp dịch vụ?

DTO là một đối tượng phản hồi / yêu cầu, nó có ý nghĩa nếu bạn sử dụng nó để liên lạc. Nếu bạn sử dụng các mô hình miền trong lớp trình bày của mình (MVC-Bộ điều khiển / Chế độ xem, WebForms, ConsoleApp), thì lớp trình bày được liên kết chặt chẽ với miền của bạn, mọi thay đổi trong miền yêu cầu bạn thay đổi bộ điều khiển của mình.

có vẻ như sẽ không có ý nghĩa gì khi tạo DTO giống như mô hình miền)

Đây là một trong những bất lợi của DTO đối với đôi mắt mới. Ngay bây giờ, bạn đang nghĩ sao chép mã , nhưng khi dự án của bạn mở rộng thì nó sẽ có ý nghĩa hơn nhiều, đặc biệt là trong môi trường nhóm nơi các nhóm khác nhau được gán cho các lớp khác nhau.

DTO có thể thêm độ phức tạp bổ sung cho ứng dụng của bạn, nhưng các lớp của bạn cũng vậy. DTO là một tính năng đắt tiền trong hệ thống của bạn, chúng không miễn phí.

Tại sao nên sử dụng DTO

Bài viết này cung cấp cả ưu điểm và nhược điểm của việc sử dụng DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Tóm tắt như sau:

Khi nào sử dụng

  • Đối với các dự án lớn.
  • Tuổi thọ dự án là 10 năm trở lên.
  • Chiến lược, nhiệm vụ quan trọng ứng dụng.
  • Các đội lớn (hơn 5)
  • Các nhà phát triển được phân phối theo địa lý.
  • Các miền và trình bày là khác nhau.
  • Giảm trao đổi dữ liệu trên cao (mục đích ban đầu của DTO)

Khi không sử dụng

  • Dự án quy mô vừa và nhỏ (tối đa 5 thành viên)
  • Thời gian dự án là 2 năm hoặc lâu hơn.
  • Không có nhóm riêng cho GUI, phụ trợ, v.v.

Luận cứ chống lại DTO

Đối số với DTO

  • Không có DTO, phần trình bày và tên miền được liên kết chặt chẽ. (Điều này là ổn cho các dự án nhỏ.)
  • Ổn định giao diện / API
  • Có thể cung cấp tối ưu hóa cho lớp trình bày bằng cách trả về một DTO chỉ chứa các thuộc tính hoàn toàn bắt buộc. Sử dụng phép chiếu linq , bạn không phải kéo toàn bộ thực thể.
  • Để giảm chi phí phát triển, hãy sử dụng các công cụ tạo mã

3
Xin chào, cảm ơn bạn đã trả lời, đây thực sự là một bản tóm tắt hay và cũng cảm ơn vì các liên kết. Câu của tôi "Đôi khi dịch vụ cần trả về đối tượng dữ liệu không được xác định trong miền" đã bị chọn sai, điều đó có nghĩa là dịch vụ kết hợp một số DO từ một kho lưu trữ (ví dụ: thuộc tính) và tạo một POCO như một thành phần của các thuộc tính này (dựa trên về logic kinh doanh). Một lần nữa, cảm ơn cho câu trả lời thực sự tốt đẹp.
Robert Goldwein

1
Một xem xét hiệu suất quan trọng là cách các mô hình miền hoặc DTO đó được trả về từ dịch vụ của bạn. Với EF, nếu bạn nhận ra một truy vấn để trả về một tập hợp cụ thể các mô hình miền (ví dụ: với .ToArray () hoặc ToList ()), bạn chọn tất cả các cột để điền vào các đối tượng đã nhận ra. Thay vào đó, nếu bạn chiếu DTO trong truy vấn, thì EF đủ thông minh để chỉ chọn các cột cần thiết để điền DTO của bạn, có thể truyền dữ liệu ít hơn đáng kể trong một số trường hợp.
khịt mũi

10
Bạn có thể ánh xạ các đối tượng của mình 'bằng tay'. Tôi biết, công cụ nhàm chán, nhưng mất 2-3 phút cho mỗi mô hình và luôn có khả năng mang đến nhiều vấn đề khi bạn sử dụng nhiều phản xạ (AutoMapper, v.v.)
Razvan Dumitru

1
cảm ơn vì đã trả lời đơn giản và với nội dung như vậy. Bạn đã làm một ân huệ cho tôi, và làm cho cuộc sống của tôi đơn giản và hạnh phúc hơn nhiều, cảm ơn bạn.
Loa

1
Chúng tôi đã có một dự án 10 triệu bị hủy vì nó chậm ... Tại sao nó chậm? Chuyển đối tượng DTO đi khắp nơi bằng cách sử dụng tính năng refelection. Hãy cẩn thận. Automapper cũng sử dụng sự phản chiếu.
RayLovless

11

Có vẻ như ứng dụng của bạn đủ lớn và phức tạp vì bạn đã quyết định thực hiện phương pháp DDD. Đừng trả lại các thực thể poco của bạn hay còn gọi là các thực thể miền và các đối tượng giá trị trong lớp dịch vụ của bạn. Nếu bạn muốn làm điều này thì hãy xóa lớp dịch vụ của bạn vì bạn không cần nó nữa! Xem các đối tượng Mô hình hoặc Truyền dữ liệu phải nằm trong lớp Dịch vụ vì chúng phải ánh xạ tới các thành viên mô hình miền và ngược lại. Vậy tại sao bạn cần phải có DTO? Trong ứng dụng phức tạp với nhiều kịch bản, bạn nên phân tách mối quan tâm của tên miền và chế độ xem bản trình bày, một mô hình miền có thể được chia thành một số DTO và một số mô hình Miền có thể được thu gọn thành DTO. Vì vậy, tốt hơn là tạo DTO của bạn trong kiến ​​trúc phân lớp, thậm chí nó sẽ giống với mô hình của bạn.

Chúng ta có nên luôn luôn sử dụng DTO để liên lạc với lớp dịch vụ không? Có, bạn phải trả lại DTO theo lớp dịch vụ của mình khi bạn nói chuyện với kho lưu trữ của bạn trong lớp dịch vụ với các thành viên mô hình miền và ánh xạ chúng tới DTO và quay lại bộ điều khiển MVC và ngược lại.

Có thể điều chỉnh các mô hình miền dựa trên những dịch vụ cần không? Một dịch vụ chỉ nói chuyện với kho lưu trữ và phương thức miền và dịch vụ miền, bạn nên giải quyết việc kinh doanh trong miền của mình dựa trên nhu cầu của bạn và đó không phải là nhiệm vụ dịch vụ để cho miền biết những gì cần thiết.

Nếu chúng ta nên tuân thủ nghiêm ngặt các DTO, chúng có nên được định nghĩa trong lớp dịch vụ không? Có, hãy thử sử dụng DTO hoặc ViewModel sau này vì chúng sẽ được ánh xạ tới các thành viên miền trong lớp dịch vụ và không nên đặt DTO trong các bộ điều khiển của ứng dụng của bạn (thử sử dụng mẫu Phản hồi yêu cầu trong lớp Dịch vụ của bạn), chúc mừng !


1
xin lỗi vì điều đó! bạn có thể thấy nó ở đây ehsanghanbari.com/blog/Post/7/ trên
Ehsan

10

Theo kinh nghiệm của tôi, bạn nên làm những gì thiết thực. "Thiết kế tốt nhất là thiết kế đơn giản nhất có hiệu quả" - Einstein. Với ý nghĩ đó ...

nếu chúng tôi sử dụng nghiêm ngặt các mô hình xem, bạn có thể trả lại các mô hình miền hoàn toàn cho bộ điều khiển hay chúng tôi nên luôn sử dụng DTO để liên lạc với lớp dịch vụ?

Hoàn toàn ổn! Nếu bạn có Thực thể Miền, Mô hình của DTO và Xem sau đó bao gồm các bảng cơ sở dữ liệu, bạn có tất cả các trường trong ứng dụng được lặp lại ở 4 vị trí. Tôi đã từng làm việc với các dự án lớn nơi Thực thể Miền và Mô hình Chế độ xem hoạt động tốt. Ngoại lệ duy nhất cho điều này là nếu ứng dụng được phân phối và lớp dịch vụ nằm trên một máy chủ khác, trong trường hợp đó các DTO được yêu cầu gửi qua dây vì lý do nối tiếp.

Nếu vậy, điều chỉnh các mô hình miền dựa trên những dịch vụ nào cần? (Thành thật mà nói tôi không nghĩ vậy, vì các dịch vụ nên tiêu thụ những gì tên miền có.)

Nói chung, tôi đồng ý và nói không bởi vì mô hình Miền thường phản ánh logic kinh doanh và thường không được định hình bởi người tiêu dùng logic đó.

Nếu chúng ta nên tuân thủ nghiêm ngặt các DTO, chúng có nên được định nghĩa trong lớp dịch vụ không? (Tôi nghĩ vậy.)

Nếu bạn quyết định sử dụng chúng, tôi đồng ý và nói có, lớp Dịch vụ là nơi hoàn hảo vì nó sẽ trả lại các DTO vào cuối ngày.

Chúc may mắn!


8

Tôi đến bữa tiệc muộn, nhưng đây là một câu hỏi phổ biến và quan trọng mà tôi cảm thấy bắt buộc phải trả lời.

Theo "dịch vụ", bạn có nghĩa là "Lớp ứng dụng" được mô tả bởi Evan trong cuốn sách màu xanh ? Tôi sẽ cho rằng bạn làm, trong trường hợp đó, câu trả lời là họ không nên trả lại DTO. Tôi đề nghị đọc chương 4 trong cuốn sách màu xanh, có tiêu đề "Cô lập tên miền".

Trong chương đó, Evans nói như sau về các lớp:

Phân vùng một chương trình phức tạp thành các lớp. Phát triển một thiết kế trong mỗi lớp gắn kết và chỉ phụ thuộc vào các lớp bên dưới.

Có lý do tốt cho việc này. Nếu bạn sử dụng khái niệm thứ tự từng phần làm thước đo độ phức tạp của phần mềm thì việc có một lớp phụ thuộc vào một lớp ở trên nó sẽ làm tăng độ phức tạp, làm giảm khả năng bảo trì.

Áp dụng điều này cho câu hỏi của bạn, DTO thực sự là một bộ chuyển đổi là mối quan tâm của lớp Giao diện / Trình bày người dùng. Hãy nhớ rằng giao tiếp từ xa / quá trình chính xác là mục đích của DTO (đáng chú ý là trong bài đăng đó, Fowler cũng lập luận rằng DTOs là một phần của lớp dịch vụ, mặc dù anh ta không nhất thiết phải nói ngôn ngữ DDD).

Nếu lớp ứng dụng của bạn phụ thuộc vào các DTO đó, thì nó phụ thuộc vào một lớp ở trên và độ phức tạp của bạn tăng lên. Tôi có thể đảm bảo rằng điều này sẽ làm tăng khó khăn trong việc duy trì phần mềm của bạn.

Ví dụ, điều gì sẽ xảy ra nếu hệ thống của bạn giao tiếp với một số loại hệ thống hoặc máy khách khác, mỗi loại yêu cầu DTO của riêng chúng? Làm thế nào để bạn biết DTO một phương thức dịch vụ ứng dụng của bạn sẽ trả về? Bạn thậm chí sẽ giải quyết vấn đề đó như thế nào nếu ngôn ngữ bạn chọn không cho phép quá tải một phương thức (phương thức dịch vụ, trong trường hợp này) dựa trên loại trả về? Và ngay cả khi bạn tìm ra một cách, tại sao lại vi phạm Lớp ứng dụng của bạn để hỗ trợ mối quan tâm của lớp Trình bày?

Trong thực tế, đây là một bước xuống một con đường sẽ kết thúc trong một kiến ​​trúc spaghetti. Tôi đã thấy loại phá hủy này và kết quả của nó trong kinh nghiệm của riêng tôi.

Nơi tôi hiện đang làm việc, các dịch vụ trong Lớp đối tượng trả về các đối tượng miền. Chúng tôi không coi đây là một vấn đề vì lớp Giao diện (tức là UI / Bản trình bày) phụ thuộc vào lớp Miền nằm bên dưới nó. Ngoài ra, sự phụ thuộc này được giảm thiểu thành loại phụ thuộc "chỉ tham chiếu" vì:

a) Lớp Giao diện chỉ có thể truy cập các đối tượng Miền này dưới dạng các giá trị trả về chỉ đọc bằng các lệnh gọi đến lớp Ứng dụng

b) các phương thức trên các dịch vụ trong Lớp ứng dụng chỉ chấp nhận làm đầu vào "thô" (giá trị dữ liệu) hoặc tham số đối tượng (để giảm số lượng tham số khi cần thiết) được xác định trong lớp đó. Cụ thể, các dịch vụ ứng dụng không bao giờ chấp nhận các đối tượng Miền làm đầu vào.

Lớp giao diện sử dụng các kỹ thuật ánh xạ được xác định trong chính lớp giao diện để ánh xạ từ các đối tượng miền sang DTOs. Một lần nữa, điều này giữ cho các DTO tập trung vào việc trở thành các bộ điều hợp được điều khiển bởi Lớp giao diện.


1
Câu hỏi nhanh. Tôi hiện đang quay cuồng về những gì sẽ trở lại từ lớp ứng dụng của mình. Trả lại các thực thể miền từ lớp ứng dụng cảm thấy sai. Tôi có thực sự muốn rò rỉ tên miền ra "bên ngoài" không? Vì vậy, tôi đã suy nghĩ về các DTO từ lớp ứng dụng. Nhưng điều đó thêm một mô hình khác. Trong phản hồi của bạn, bạn nói rằng bạn trả về các mô hình Miền dưới dạng "giá trị trả về chỉ đọc". Làm thế nào để bạn làm điều đó? Tức là, làm thế nào để bạn làm cho họ chỉ đọc?
Michael Andrew

Tôi nghĩ rằng tôi sẽ chấp nhận vị trí của bạn. Dịch vụ ứng dụng trả về các mô hình Miền. Các lớp bộ điều hợp cổng (REST, trình bày, v.v.) sau đó dịch chúng thành mô hình của riêng chúng (xem mô hình hoặc biểu diễn). Thêm một mô hình DTO giữa ứng dụng và bộ điều hợp cổng có vẻ quá mức cần thiết. Các mô hình miền quay lại vẫn tuân thủ DIP và logic miền vẫn nằm trong ngữ cảnh giới hạn (không nhất thiết phải nằm trong ranh giới ứng dụng. Nhưng điều đó có vẻ như là một sự thỏa hiệp tốt).
Michael Andrew

@MichaelAndrews, rất vui khi biết rằng câu trả lời của tôi đã giúp. Re: câu hỏi của bạn về các đối tượng được trả về là chỉ đọc, bản thân các đối tượng không thực sự chỉ đọc (tức là không thay đổi). Ý tôi là nó không xảy ra trong thực tế (ít nhất là theo kinh nghiệm của tôi). Để cập nhật một đối tượng miền, Lớp giao diện sẽ phải a) tham chiếu kho lưu trữ của đối tượng miền hoặc b) gọi lại vào Tầng ứng dụng để cập nhật đối tượng mà nó vừa nhận được. Một trong những điều này là vi phạm rõ ràng về thực hành DDD tốt đến mức tôi thấy chúng phải tự thi hành. Hãy thoải mái đưa ra câu trả lời nếu bạn quan tâm.
BitMask777

Câu trả lời này rất trực quan với tôi vì nhiều lý do. Đầu tiên, chúng ta có thể sử dụng lại cùng một Lớp ứng dụng cho một số UI (API, Bộ điều khiển) và mỗi lớp có thể biến đổi mô hình khi nó thấy phù hợp. Thứ hai, nếu chúng ta chuyển đổi mô hình thành DTO trong Ứng dụng. Lớp, điều đó có nghĩa là DTO được xác định trong Ứng dụng. Lớp, điều này có nghĩa là DTO hiện là một phần của Bối cảnh bị ràng buộc của chúng tôi (không nhất thiết phải là Miền!) - điều này chỉ cảm thấy sai.
Robotron

1
Tôi vừa định hỏi bạn một câu hỏi tiếp theo và sau đó thấy bạn đã trả lời nó: "dịch vụ ứng dụng không bao giờ chấp nhận các đối tượng Miền làm đầu vào". Tôi sẽ +1 lần nữa nếu tôi có thể.
Robotron

4

Cho đến nay, chúng tôi sử dụng các mô hình miền (chủ yếu là các thực thể) trên tất cả các lớp và chúng tôi chỉ sử dụng các DTO làm mô hình khung nhìn (trong bộ điều khiển, dịch vụ trả về (các) mô hình miền và bộ điều khiển tạo mô hình khung nhìn, được chuyển đến dạng xem).

Vì Mô hình miền cung cấp thuật ngữ ( Ngôn ngữ phổ biến ) cho toàn bộ ứng dụng của bạn, tốt hơn là sử dụng Mô hình miền rộng rãi.

Lý do duy nhất để sử dụng ViewModels / DTOs là việc triển khai mẫu MVC trong ứng dụng của bạn để phân tách View(bất kỳ loại lớp trình bày nào) và Model(Mô hình miền). Trong trường hợp này, bản trình bày và mô hình miền của bạn được ghép lỏng lẻo.

Đôi khi dịch vụ cần trả về đối tượng dữ liệu không được xác định trong miền và sau đó chúng tôi phải thêm đối tượng mới vào miền không được ánh xạ hoặc tạo đối tượng POCO (điều này thật xấu, vì một số dịch vụ trả về mô hình miền, một số dịch vụ trả lại hiệu quả DTOs).

Tôi giả sử rằng bạn nói về các dịch vụ Logic / Ứng dụng / Tên miền.

Tôi đề nghị bạn trả lại các thực thể miền khi bạn có thể. Nếu cần phải trả lại thông tin bổ sung, có thể chấp nhận trả lại DTO chứa một số thực thể miền.

Đôi khi, những người sử dụng khung phần 3, tạo ra proxy trên các thực thể miền, gặp khó khăn khi phơi bày các thực thể miền khỏi dịch vụ của họ nhưng đó chỉ là vấn đề sử dụng sai.

Câu hỏi đặt ra là - nếu chúng ta sử dụng nghiêm ngặt các mô hình xem, liệu có thể trả lại các mô hình miền hoàn toàn cho bộ điều khiển hay chúng ta nên luôn sử dụng DTO để liên lạc với lớp dịch vụ?

Tôi muốn nói rằng nó là đủ để trả về các thực thể miền trong 99,9% trường hợp.

Để đơn giản hóa việc tạo DTO và ánh xạ các thực thể miền của bạn vào chúng, bạn có thể sử dụng AutoMapper .


4

Nếu bạn trả lại một phần của mô hình miền, nó sẽ trở thành một phần của hợp đồng. Một hợp đồng khó thay đổi, vì những thứ bên ngoài bối cảnh của bạn phụ thuộc vào nó. Như vậy, bạn sẽ khó biến một phần của mô hình miền của mình.

Một khía cạnh rất quan trọng của một mô hình miền là nó rất dễ thay đổi. Điều này làm cho chúng tôi linh hoạt với các yêu cầu thay đổi của tên miền.


4

Đến bữa tiệc muộn, nhưng tôi phải đối mặt với cùng một kiểu kiến ​​trúc và tôi chỉ nghiêng về hướng DỪNG từ dịch vụ. Điều này chủ yếu là do tôi đã quyết định chỉ sử dụng các đối tượng / tập hợp miền để duy trì tính hợp lệ trong đối tượng, do đó chỉ khi cập nhật, tạo hoặc xóa. Khi chúng tôi truy vấn dữ liệu, chúng tôi chỉ sử dụng EF làm kho lưu trữ và ánh xạ kết quả tới các DTO. Điều này giúp chúng tôi tự do tối ưu hóa các truy vấn đọc và không thích ứng chúng với các đối tượng kinh doanh, thường sử dụng các chức năng cơ sở dữ liệu vì chúng nhanh.

Mỗi phương thức dịch vụ xác định hợp đồng riêng của mình và do đó dễ duy trì hơn theo thời gian. Tôi hi vọng.


1
Sau nhiều năm, chúng tôi đã đi đến kết luận tương tự, chính xác là vì lý do bạn đề cập ở đây.
Robert Goldwein

@RobertGoldwein Thật tuyệt! Tôi cảm thấy tự tin hơn với quyết định của mình bây giờ. :-)
Niklas Wulff

@NiklasWulff: vì vậy, Dtos trong câu hỏi hiện là một phần của hợp đồng Lớp ứng dụng, tức là một phần của lõi / miền. Còn các kiểu trả về API Web thì sao? Bạn có để lộ Dtos được đề cập trong câu trả lời của mình không hoặc bạn có Mô hình xem chuyên dụng được xác định trong lớp API Web không? Hay nói cách khác: bạn có ánh xạ Dtos để Xem Mô hình không?
Robotron

1
@Robotron Chúng tôi không có API Web, chúng tôi sử dụng MVC. Vì vậy, có, chúng tôi ánh xạ dto: s sang các mô hình xem khác nhau. Thông thường một mô hình khung nhìn chứa nhiều nội dung khác để hiển thị trang web, vì vậy dữ liệu từ dto: s chỉ chiếm một phần của mô hình xem
Niklas Wulff

2

Tôi đề nghị phân tích hai câu hỏi sau:

  1. Các lớp trên của bạn (tức là xem & xem mô hình / bộ điều khiển) đang tiêu thụ dữ liệu theo cách khác với những gì lớp miền lộ ra? Nếu có rất nhiều ánh xạ được thực hiện hoặc thậm chí logic liên quan, tôi sẽ đề nghị xem lại thiết kế của bạn: có lẽ nó sẽ gần hơn với cách dữ liệu được sử dụng thực sự.

  2. Làm thế nào có khả năng là bạn thay đổi sâu sắc lớp trên của bạn? (ví dụ: hoán đổi ASP.NET cho WPF). Nếu điều này không giống lắm và kiến ​​trúc của bạn không phức tạp lắm, bạn có thể nên tiết lộ càng nhiều thực thể miền càng tốt.

Tôi e rằng đây là một chủ đề khá rộng và nó thực sự đi sâu vào mức độ phức tạp của hệ thống và các yêu cầu của nó.


Trong trường hợp của chúng tôi, lớp trên chắc chắn sẽ không thay đổi. Trong một số trường hợp, dịch vụ trả về đối tượng POCO khá độc đáo (được xây dựng từ nhiều tên miền - ví dụ: người dùng và tệp mà anh ta sở hữu), trong một số trường hợp, dịch vụ trả về mô hình miền đơn giản - ví dụ: kết quả của "FindUserByEmail () sẽ trả về mô hình miền Người dùng - và Đây là mối quan tâm của tôi, đôi khi (các) dịch vụ của chúng tôi trả về mô hình miền, đôi khi DTO mới - và tôi không thích sự không nhất quán này, tôi đã đọc nhiều bài viết nhất có thể và dường như đa số đồng ý rằng mặc dù Mô hình miền ánh xạ <-> DTO là 1: 1, mô hình miền không nên rời khỏi lớp dịch vụ - vì vậy tôi bị rách.
Robert Goldwein

Trong một kịch bản như vậy và với điều kiện là bạn có thể chịu được nỗ lực phát triển thêm, tôi cũng sẽ đi với ánh xạ để việc xếp lớp của bạn phù hợp hơn.
jnovo

1

Theo kinh nghiệm của tôi, trừ khi bạn đang sử dụng mẫu UI OO (như các đối tượng trần trụi), việc phơi bày các đối tượng miền cho UI là một ý tưởng tồi. Điều này là do ứng dụng phát triển, nhu cầu từ UI thay đổi và buộc các đối tượng của bạn phải điều chỉnh những thay đổi đó. Cuối cùng, bạn phục vụ 2 thạc sĩ: UI và DOMAIN, đó là một trải nghiệm rất đau đớn. Hãy tin tôi, bạn không muốn ở đó. Mô hình UI có chức năng giao tiếp với người dùng, mô hình DOMAIN để giữ các quy tắc kinh doanh và các mô hình kiên trì liên quan đến việc lưu trữ dữ liệu một cách hiệu quả. Tất cả đều giải quyết các nhu cầu khác nhau của ứng dụng. Tôi đang ở giữa viết một bài đăng trên blog về điều này, sẽ thêm nó khi nó hoàn thành.

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.