2013-09-16 41 views
26

Chúng tôi đang xây dựng một ứng dụng web bằng AngularJS, C#, ASP.Net Web API và Fluent NHibernate. Chúng tôi đã quyết định sử dụng DTO để chuyển dữ liệu sang lớp trình bày (chế độ xem góc). Tôi đã có một vài nghi ngờ về cấu trúc chung và đặt tên cho DTO. Đây là một ví dụ để minh họa cho kịch bản của tôi. phép nói rằng tôi có một thực thể miền gọi là khách hàng trông giống như:Quy ước đặt tên DTO, mô hình và kế thừa

public class Customer 
    { 
     public virtual int Id { get; set; } 
     public virtual string Name { get; set; } 
     public virtual Address Address { get; set; } 
     public virtual ICollection<Account> Accounts { get; set; } 
    } 

Bây giờ, trong quan điểm của tôi/lớp trình bày tôi cần phải lấy hương vị khác nhau của khách hàng như:

1) Chỉ cần Id và Tên 2) Id, Name và Address 3) Id, Tên, Địa chỉ và Accounts

tôi đã tạo ra một tập hợp các DTOs để thực hiện điều này:

public class CustomerEntry 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class CustomerWithAddress : CustomerEntry 
{ 
    public AddressDetails Address { get; set; } 
} 

public class CustomerWithAddressAndAccounts : CustomerWithAddress 
{ 
    public ICollection<AccountDetails> Accounts { get; set; } 
} 

AddressDetails và AccountDetails là DTO có tất cả các thuộc tính của các thực thể Domain tương ứng của chúng.

Tính năng này hoạt động tốt cho truy vấn và truy xuất dữ liệu; câu hỏi là tôi sử dụng gì để chèn và cập nhật. Trong quá trình tạo hồ sơ khách hàng mới, tên và địa chỉ là bắt buộc và các tài khoản là tùy chọn .. vì vậy nói cách khác tôi cần một đối tượng có tất cả các thuộc tính của khách hàng. Do đó sự nhầm lẫn:

1) Tôi phải làm gì để chèn và cập nhật? CustomerWithAddressAndAccounts DTO có mọi thứ trong đó nhưng tên của nó có vẻ hơi khó xử khi được sử dụng để chèn/cập nhật.

2) Tôi có tạo một DTO khác không .. nếu có, không phải là trùng lặp vì DTO mới sẽ chính xác giống như CustomerWithAddressAndAccounts?

3) Cuối cùng nhưng không kém phần quan trọng, tính năng strileure kế thừa DTO được mô tả ở trên có vẻ phù hợp với yêu cầu không? Có cách nào khác để mô hình hóa điều này không?

Tôi đã đi qua các bài đăng khác về chủ đề này nhưng không thể thực hiện nhiều tiến bộ. Một điều tôi đã làm là để tránh sử dụng hậu tố "DTO" trong tên lớp. Tôi nghĩ rằng nó cảm thấy một chút không cần thiết.

Rất thích nghe những suy nghĩ của bạn

Cảm ơn

Trả lời

9

Khuyến nghị là bạn chỉ nên có một lớp DTO cho từng đối tượng hậu tố với DTO ví dụ CustomerEntryDTO cho số Customerentity (nhưng bạn chắc chắn có thể sử dụng phân cấp thừa kế theo lựa chọn và yêu cầu).

Hơn nữa, thêm tóm tắt DTOBase loại lớp cơ sở hoặc giao diện; và không sử dụng các thừa kế thừa kế sâu sắc như vậy cho mỗi Địa chỉ, Tài khoản và các thuộc tính khác để được đưa vào các DTO trẻ em. Thay vào đó, bao gồm các thuộc tính trong cùng một lớp CustomerEntryDTO (nếu có thể) như sau:

[Serializable] 
public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public AddressDetails Address { get; set; } //Can remain null for some Customers 
    public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer 
} 

Hơn nữa, DTOs bạn nên được serializable để được thông qua quá trình qua các biên giới.

Đối hơn trên mô hình DTO, tham khảo bên dưới bài viết:

Data Transfer Object

MSDN

Edit: Trong trường hợp bạn không muốn gửi sản phẩm nhất định trên dây (Tôi biết bạn sẽ cần phải có điều kiện như vậy sẽ cần phải khám phá thêm về điều này), bạn có thể loại trừ chúng khỏi cơ chế Serialization bằng cách sử dụng các thuộc tính như NonSerialized (nhưng nó chỉ hoạt động trên các trường và không thuộc tính, xem bài viết workaround để sử dụng với các thuộc tính: NonSerialized on property). Bạn cũng có thể tạo thuộc tính tùy chỉnh của riêng mình như ExcludeFromSerializationAttribute và áp dụng nó cho thuộc tính bạn không muốn gửi mỗi lần qua dây dựa trên các quy tắc/điều kiện nhất định. Xem thêm:Conditional xml serialization

Chỉnh sửa 2: Sử dụng giao diện để tách các thuộc tính khác nhau trong một CustomerEntryDTO lớp. Xem Nguyên tắc phân đoạn giao diện trên Google hoặc MSDN. Tôi sẽ cố gắng đưa ra một lời giải thích mẫu sau.

+0

Cảm ơn bạn đã trả lời. Một trong những động lực cho việc sử dụng nhiều lớp DTO là một chút rõ ràng hơn trong việc xác định những gì DTO được sử dụng cho. Ngoài ra, nếu bạn chỉ cần Id và Tên, bạn có nên gửi đầy đủ CustomerEntryDTO (mà bạn đã mô tả) qua dây không? – Sennin

+0

@Sennin Tôi đã chỉnh sửa câu trả lời dựa trên nhận xét của bạn nhưng tôi nghĩ câu trả lời của tôi sẽ vẫn chưa hoàn chỉnh cho bạn. Có thể tôi sẽ chỉnh sửa nó sau này để thêm nhiều hơn vào bình luận ở trên của bạn. – VS1

+0

@Sennin xin xem sửa của tôi 2. – VS1

0

Vì mục 1 của bạn, để chèn và cập nhật, tốt hơn nên sử dụng mẫu Lệnh. Theo CQRS, bạn không cần DTO. Xem xét sơ đồ này: CQRS — basic patterns qua blogs.msdn.com

+0

Bạn vẫn cần một DTO cho phía truy vấn của mọi thứ để không phải là câu trả lời hay. –

0

để tôi sử dụng gì để chèn và cập nhật?

  1. hoạt động dịch vụ thường được xác định trong mối quan hệ rất gần gũi với hoạt động kinh doanh. Ngôn ngữ kinh doanh không nói về "chèn" và "cập nhật", cũng không phải dịch vụ.

  2. Dịch vụ quản lý khách hàng có thể có một số hoạt động Register lấy tên khách hàng và có thể một số thông số tùy chọn khác.

Tôi có tạo một DTO khác không?

Có, bạn nên tạo một DTO khác.

Đôi khi hợp đồng dịch vụ hoạt động có thể đủ và không có cần phải xác định một DTO riêng cho một hoạt động cụ thể:

function Register(UserName as String, Address as Maybe(of String)) as Response 

Nhưng phần lớn thời gian nó là tốt hơn để xác định một lớp DTO riêng biệt thậm chí chỉ cho một hoạt động dịch vụ duy nhất:

class RegisterCommand 
    public UserName as String 
    public Address as Maybe(of String) 
end class 

function Register(Command as RegisterCommand) as Response 

RegisterCommand DTO có thể trông rất giống với CustomerWithAddress DTO vì nó có cùng trường nhưng trên thực tế những 2 DTOs có ý nghĩa rất khác nhau và không thay thế nhau.

Ví dụ: CustomerWithAddress chứa AddressDetails, trong khi đại diện địa chỉ String đơn giản có thể đủ để đăng ký khách hàng.

Sử dụng DTO riêng cho từng hoạt động dịch vụ cần nhiều thời gian hơn để viết nhưng dễ bảo trì hơn.

Các vấn đề liên quan