2013-09-16 45 views
26

Budujemy aplikację internetową za pomocą AngularJS, C#, ASP.Net Web API i Fluent NHibernate. Zdecydowaliśmy się użyć DTO do przesyłania danych do warstwy prezentacji (widoki kątowe). Miałem kilka wątpliwości dotyczących ogólnej struktury i nazewnictwa DTO. Oto przykład ilustrujący mój scenariusz. Powiedzmy mam podmiot domeny o nazwie klienta, który wygląda tak:Konwencje nazewnictwa, modelowania i dziedziczenia DTO

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; } 
    } 

Teraz w moich poglądów/warstwa prezentacji muszę pobierać różne smaki Klienta jak:

1) Just Identyfikator i nazwisko 2) ID, nazwa i adres 3) id, nazwisko, adres i Konta

Stworzyłem zestaw DTOs do osiągnięcia tego celu:

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; } 
} 

Dane adresowe i szczegóły konta to DTO, które mają wszystkie właściwości odpowiadających im encji domeny.

Działa to dobrze w przypadku zapytań i wyszukiwania danych; pytanie brzmi, co używam do wstawiania i aktualizacji. Podczas tworzenia nowego rekordu klienta nazwa i adres są obowiązkowe, a konta są opcjonalne. Innymi słowy, potrzebuję obiektu ze wszystkimi właściwościami klienta. Stąd zamieszanie:

1) Do czego służy wstawianie i aktualizowanie? CustomerTOithAddressAndAccounts DTO ma wszystko w sobie, ale jego nazwa wydaje się nieco niewygodna do użycia przy wstawianiu/aktualizacjach.

2) Czy mogę utworzyć kolejny DTO ... jeśli to zrobię, czy to nie będzie duplikowanie, ponieważ nowy DTO będzie dokładnie taki jak CustomerWithAddressAndAccounts?

3) Wreszcie, czy opisany powyżej schemat dziedziczenia DTO wydaje się być dobrze dopasowany do wymagań? Czy istnieją inne sposoby na modelowanie tego?

Przeszedłem inne posty na ten temat, ale nie mogłem zrobić wiele naprzód. Jedną z rzeczy, którą zrobiłem, było uniknięcie użycia przyrostka "DTO" w nazwach klas. Myślę, że to trochę niepotrzebne.

Chcielibyśmy usłyszeć wasze myśli

Dzięki

Odpowiedz

9

Zalecenie to, że należy po prostu mieć jedną klasę DTO dla każdego podmiotu z przedrostkiem np DTOCustomerEntryDTO dla modelu Customerentity (ale można oczywiście użyć hierarchii dziedziczenia zgodnie z wyborem i wymaganiami).

Co więcej, dodaj streszczenie DTOBase rodzaj klasy bazowej lub interfejsu; i nie stosuj tak głębokich dziedziczenia dziedziczenia dla każdego adresu, konta i innych właściwości, które należy uwzględnić w DTO dla dzieci. Przeciwnie, to te właściwości w tej samej klasie CustomerEntryDTO (jeśli to możliwe), jak poniżej:

[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 
} 

Ponadto twoi DTOs powinien być możliwy do serializacji być przekazywane przez granice procesu.

Dla więcej na wzór DTO, patrz poniżej artykułach:

Data Transfer Object

MSDN

Edit: W przypadku, gdy nie chcesz wysłać pewne właściwości nad drutu (Wiem, że musiałbyś to zrobić warunkowo, więc musiałbyś dowiedzieć się więcej na ten temat), możesz wykluczyć je z mechanizmu serializacji używając atrybutów takich jak NonSerialized (ale działa tylko na polach, a nie właściwościach, patrz artykuł dotyczący obejścia dla właściwości: NonSerialized on property). Można również utworzyć własny atrybut niestandardowy, taki jak ExcludeFromSerializationAttribute i zastosować go do właściwości, których nie chcesz wysyłać za każdym razem za pomocą przewodu w oparciu o pewne reguły/warunki. zobacz także:Conditional xml serialization

Edit 2: Stosować interfejsy do rozdzielania różnych właściwościach w jednym CustomerEntryDTO klasie. Zobacz zasadę segregacji interfejsu w Google lub MSDN. Postaram się umieścić przykładowe wyjaśnienie później.

+0

Dziękuję za odpowiedź. Jedną z motywacji do korzystania z wielu klas DTO było nieco bardziej ekspresyjne zdefiniowanie, do czego służy DTO. Ponadto, jeśli potrzebujesz tylko identyfikatora i nazwy, czy naprawdę chcesz wysłać pełnowartościowy CustomerEntryDTO (który opisałeś) przez przewód? – Sennin

+0

@Sennin Edytowałem swoją odpowiedź na podstawie Twojego komentarza, ale myślę, że moja odpowiedź byłaby dla ciebie niekompletna. Może będę edytować go później, aby dodać więcej na powyższy komentarz. – VS1

+0

@Sennin pls zobacz moją edycję 2. – VS1

0

Od pozycji 1, w przypadku wstawek i aktualizacji lepiej użyć wzorca polecenia. Według CQRS nie potrzebujesz DTO. Rozważmy następujący schemat: CQRS — basic patterns poprzez blogs.msdn.com

+0

Nadal potrzebujesz DTO dla strony zapytań, więc nie jest to dobra odpowiedź. –

0

Czego użyć do wstawiania i aktualizacji?

  1. operacje serwisowe są zazwyczaj definiowane w bardzo ścisłym związku z działalnością gospodarczą. Język biznesowy nie mówi w kategoriach "wkładek" i "aktualizacji", ani usług.

  2. Usługa zarządzania obsługą klienta prawdopodobnie będzie miała operację Register, która ma nazwę klienta i może niektóre inne opcjonalne parametry.

utworzyć kolejną dto?

Tak, należy utworzyć kolejne DTO.

Czasami usługa kontrakt operacja może być dość i nie ma potrzeby, aby zdefiniować oddzielny dto dla danej operacji:

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

Ale większość czasu lepiej jest zdefiniować oddzielną klasę DTO nawet tylko pojedyncza operacja usługa:

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

function Register(Command as RegisterCommand) as Response 

RegisterCommand DTO może wyglądać bardzo podobnie do CustomerWithAddress DTO ponieważ ma te same pola, ale w rzeczywistości te 2 DTOs mają bardzo różne znaczenia i nie zastępują siebie.Na przykład CustomerWithAddress zawiera AddressDetails, podczas gdy prosta reprezentacja adresu może być wystarczająca do zarejestrowania klienta.

Korzystanie z oddzielnego urządzenia DTO dla każdej operacji serwisowej wymaga więcej czasu, ale łatwiejsze do zapisania.