Có phải là thực hành tốt để sử dụng các đối tượng thực thể làm đối tượng truyền dữ liệu?


29

Tôi tự hỏi bởi vì nếu có, tại sao Entity Framework không cung cấp logic để tạo một đối tượng mới có cùng thuộc tính để truyền dữ liệu giữa các lớp?

Tôi sử dụng các đối tượng thực thể mà tôi tạo ra với khung thực thể.


3
Tôi nghĩ rằng đây là một câu hỏi hay nhưng tôi thực sự không thể nói vì nó rất khó đọc Tôi không biết làm thế nào để sửa nó. Vui lòng chỉnh sửa câu hỏi của bạn.
candied_orange

1
@CandiedOrange +1, và nó khiến mọi thứ trở nên đáng sợ hơn khi điều này nhận được rất nhiều sự ủng hộ.
guillaume31

Câu trả lời:


23

Điêu đo phụ thuộc vao bạn.

Hầu hết mọi người sẽ nói với bạn rằng đó không phải là một thực hành tốt nhưng bạn có thể thoát khỏi nó trong một số trường hợp.

EF không bao giờ chơi độc đáo với DDD vì nhiều lý do, nhưng hai lý do nổi bật: bạn không thể có các hàm tạo tham số hóa trên các thực thể của mình và bạn không thể gói gọn các bộ sưu tập. DDD dựa vào đó, vì mô hình miền nên bao gồm cả dữ liệu và hành vi.

Theo một cách nào đó, EF buộc bạn phải có một mô hình miền thiếu máu và trong trường hợp này bạn có thể sử dụng các thực thể làm DTOs. Bạn có thể gặp phải một số vấn đề nếu bạn sử dụng các thuộc tính điều hướng nhưng bạn có thể tuần tự hóa các thực thể đó và gửi chúng qua dây. Nó có thể không thực tế mặc dù. Bạn sẽ phải kiểm soát việc tuần tự hóa cho từng thực thể có các thuộc tính bạn không cần gửi qua. Cách dễ dàng hơn là chỉ cần thiết kế các lớp riêng biệt được thiết kế để truyền dữ liệu. Các thư viện như AutoMapper được tạo ra cho mục đích này.

Ví dụ: Giả sử bạn có một lớp được gọi Personvới định nghĩa sau:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

Giả sử bạn muốn hiển thị một danh sách các nhân viên nơi nào đó, nó có thể được thực hiện để gửi chỉ là Id, FirstNameLastName. Nhưng bạn sẽ phải gửi qua tất cả các thuộc tính không liên quan khác. Đó không phải là vấn đề lớn nếu bạn không quan tâm đến quy mô của phản hồi nhưng ý tưởng chung là chỉ gửi dữ liệu liên quan. Mặt khác, bạn có thể thiết kế một API trả về danh sách những người và trong trường hợp đó, việc gửi tất cả các thuộc tính có thể là cần thiết, do đó, có ý nghĩa để tuần tự hóa và gửi các thực thể. Trong trường hợp này, việc tạo một lớp DTO là điều gây tranh cãi. Một số người thích trộn lẫn các thực thể và DTO, một số người thì không.

Để trả lời câu hỏi cập nhật của bạn, EF là một ORM. Công việc của nó là ánh xạ các bản ghi cơ sở dữ liệu tới các đối tượng và ngược lại. Những gì bạn làm với những đối tượng đó trước và sau khi đi qua EF không phải là một phần của mối quan tâm. Cũng không nên.


1
Tóm tắt ngắn gọn. Sự khác biệt giữa DTO và POCO là gì? Họ không chỉ giữ dữ liệu?
Laiv

1
@ guillaume31 Bạn không thể có một mô hình miền thực sự mà không xem xét sự kiên trì. Giao diện công cộng có ích gì nếu tôi buộc phải sử dụng sự phản chiếu (không đề cập đến các loại hack khác, miễn là tài sản công cộng của tôi được hỗ trợ bởi một trường riêng có tên khác) để tải tổng hợp của tôi ở trạng thái hợp lệ? Nếu EF không cung cấp cho tôi cơ sở hạ tầng để che giấu các tập hợp của tôi bằng cách sử dụng giao diện chung của họ thì tốt hơn hết bạn nên giữ logic kinh doanh của mình ở nơi khác và bị thiếu máu miền thay vì viết thêm đĩa nồi hơi để tải chúng từ cơ sở dữ liệu.
devnull

1
Vì vậy, bạn muốn làm cho toàn bộ mô hình miền của bạn bị thiếu máu hơn là đặt tên cho bộ sưu tập công khai của bạn giống như trường riêng? (hãy đặt vấn đề của nhà xây dựng sang một bên, bởi vì nó thường chống lại miền ở nơi đầu tiên để lộ một nhà xây dựng lấy tất cả các trường của đối tượng ...)
guillaume31

1
@Konrad từ đây : As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.Tôi rất muốn có các dịch vụ ứng dụng được đưa vào thực thể của mình.
tà tà

1
@Konrad Tôi sẽ ngừng sử dụng các thực thể tên miền của mình dưới dạng DTO (nếu tôi sử dụng chúng theo cách này). DTO là hữu ích bất kể hỗ trợ của EF cho tiêm dịch vụ.
tà tà

8

Không có nó không phải là.

Lý tưởng nhất, các DTO sẽ phù hợp với kho lưu trữ liên tục của bạn (hay còn gọi là bảng cơ sở dữ liệu của bạn).

Nhưng các lớp kinh doanh của bạn không nhất thiết phải là một trận đấu. Bạn có thể cần các lớp bổ sung, hoặc tách hoặc tham gia các lớp với những gì bạn có trong cơ sở dữ liệu. Nếu ứng dụng của bạn nhỏ, bạn có thể không thực sự thấy loại vấn đề này, nhưng trong các ứng dụng từ trung bình đến lớn, điều này sẽ xảy ra thường xuyên.

Một điều nữa là các DTO là một phần của miền bất cứ điều gì liên quan đến sự kiên trì, trong khi Lớp doanh nghiệp của bạn không nên biết gì về chúng.


Một chỉ huy đối tượng là một DTO rằng các lớp kinh doanh nên biết điều gì đó về.
devnull

Tôi nghĩ rằng lớp nghiệp vụ có thể sẽ gọi đối tượng lệnh một cách gián tiếp, thông qua một giao diện. Và ý tôi là các DTO như trong các đối tượng đơn giản mang dữ liệu, không có chức năng nào cả. Tôi không chắc chắn nếu một đối tượng lệnh là DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac

1
Thông thường, các lệnh được tách thành lệnh thực tế và trình xử lý của nó. Lệnh chứa dữ liệu, trình xử lý chứa hành vi. Khi được sử dụng như thế này, phần lệnh chỉ chứa dữ liệu nhận được từ máy khách và hoạt động như một DTO giữa máy khách và lớp nghiệp vụ.
devnull

DTO không chuyển từ sự kiên trì sang tên miền, họ cũng có thể đến từ bên ngoài như trong dữ liệu đang đến (nghĩ trong API REST). Như được chỉ ra bởi devnull, các lệnh và sự kiện có phần DTO và chúng được chuyển sang lớp nghiệp vụ. Nếu xử lý là lớp kinh doanh hay không phụ thuộc vào thiết kế.
Laiv

4

Nó thực sự là một ý tưởng rất xấu. Martin Fowler có một bài viết về DTOs địa phương .

Tóm lại, DTOMẫu được sử dụng để truyền dữ liệu ngoài quy trình, ví dụ qua dây và không phải giữa các lớp trong cùng một quy trình.


Như với tất cả các phương pháp lập trình, không có một kích thước nào phù hợp với tất cả các mặt khác, chúng tôi sẽ không tranh luận và thảo luận về các mô hình và cách tiếp cận khác nhau trong mỗi ứng dụng chúng tôi xây dựng, chúng tôi chỉ luôn sử dụng những thứ giống nhau. Các DTO về cơ bản chỉ là các POPO mà họ chỉ được đặt tên để thể hiện một số ý định. Không có gì với việc sử dụng DTO để "truyền dữ liệu" giữa ví dụ: dịch vụ, bộ điều khiển và vào chế độ xem. Không có gì trong tên hoặc cấu trúc của các lớp biểu thị hoặc giới hạn từ nơi và dữ liệu được chuyển
James

4

Không, đó là một thực tế xấu.

Một số lý do:

  1. Các trường thực thể mới sẽ ở trong Dto, theo mặc định . Sử dụng thực thể có nghĩa là mọi thông tin sẽ có sẵn để được sử dụng theo mặc định. Điều này có thể khiến bạn tiết lộ thông tin hợp lý hoặc, ít nhất, làm cho hợp đồng API của bạn bị thổi phồng, với rất nhiều thông tin không được sử dụng cho những người tiêu thụ API. Tất nhiên, bạn có thể bỏ qua các trường bằng cách sử dụng một số chú thích (như @JsonIgnoretừ thế giới Java), nhưng điều này dẫn đến vấn đề tiếp theo ...
  2. Rất nhiều chú thích / điều kiện / điều khiển trên thực thể . Bạn cần kiểm soát những gì bạn muốn gửi trên Dto, khi một số tên thuộc tính thay đổi (điều này sẽ phá vỡ hợp đồng), thêm một số thuộc tính không phải từ thực thể, thứ tự của các thuộc tính, v.v ... Bạn sẽ sớm thấy đơn giản của mình thực thể có nhiều chú thích, các trường thêm và mỗi lần sẽ khó hiểu hơn những gì đang xảy ra.
  3. Ít linh hoạt . Với một Dto, bạn có thể tự do phá vỡ thông tin trong nhiều lớp hơn, thay đổi tên thuộc tính, thêm thuộc tính mới, v.v. Bạn không thể làm điều này quá dễ dàng với một thực thể là Dto.
  4. Không được tối ưu hóa . Thực thể của bạn sẽ luôn lớn hơn một Dto đơn giản. Vì vậy, bạn sẽ luôn có nhiều thông tin bị bỏ qua / tuần tự hóa và có thể nhiều thông tin không cần thiết được truyền đi.
  5. Vấn đề lười biếng . Sử dụng thực thể của một số khung (như Hibernate), nếu bạn cố truy xuất một số thông tin không được tải trong giao dịch cơ sở dữ liệu trước đó, proxy ORM sẽ không được đính kèm với giao dịch và bạn sẽ nhận được một loại "ngoại lệ lười biếng" chỉ để gọi một getphương thức của thực thể.

Vì vậy, sẽ dễ dàng và an toàn hơn khi sử dụng một số loại công cụ ánh xạ để giúp bạn thực hiện công việc này, ánh xạ các trường thực thể thành Dto.


1

Để hoàn thành những gì @Dherik đã nói, các vấn đề chính của việc sử dụng các đối tượng thực thể làm đối tượng truyền dữ liệu là:

  1. Trong giao dịch, bạn chấp nhận rủi ro để thực hiện các thay đổi được thực hiện trên thực thể của mình vì bạn sử dụng nó làm DTO (ngay cả khi bạn có thể tách rời thực thể của phiên trong giao dịch, hầu hết thời gian bạn sẽ cần kiểm tra trạng thái này trước bất kỳ sửa đổi nào trên DTO thực thể của bạn và đảm bảo rằng bạn không tham gia giao dịch hoặc phiên đã bị đóng nếu bạn không muốn các sửa đổi được duy trì).

  2. Kích thước dữ liệu bạn chia sẻ giữa máy khách và máy chủ: đôi khi bạn không muốn gửi tất cả nội dung của một thực thể đến máy khách để giảm thiểu kích thước phản hồi của yêu cầu. Việc tách DTO khỏi thực thể linh hoạt hơn, để chuyên môn hóa dữ liệu mà bạn muốn gửi trong các trường hợp sử dụng nhất định.

  3. Khả năng hiển thị và bảo trì: Bạn phải quản lý các chú thích jpa / hibernate của mình trên các trường của thực thể và duy trì các chú thích jackson để tuần tự hóa trong json tại cùng một nơi (ngay cả khi bạn có thể tách chúng khỏi thực thi thực thể để đặt chúng vào giao diện được kế thừa bởi thực thể). Sau đó, nếu bạn thay đổi nội dung DTO của mình khi thêm trường mới, một người khác có thể nghĩ rằng đó là trường của thực thể, do đó, trường của bảng có liên quan trong cơ sở dữ liệu của bạn (ngay cả khi bạn có thể sử dụng @Transientchú thích trên tất cả các trường DTO của mình đối với trường hợp ..!).

Theo tôi, nó tạo ra tiếng ồn khi bạn đọc thực thể, nhưng ý kiến ​​của tôi chắc chắn là chủ quan.

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.