2013-05-16 27 views
7

Obecnie pracuję nad projektem WWW n-tieru. Po zapoznaniu się z obiektami transferu danych i ich zaletami zdecydowaliśmy się na ten wzór. Nasza strona ASP.NET MVC nie ma bezpośredniego dostępu do EF DbContext, ale zamiast tego użyje DTO do wysyłania i odbierania danych encji. Będzie istnieć warstwa usługi/mapowania, która będzie konwertować między DTO a modelami jednostek.Tłumaczenie właściwości nawigacji po modelu modelu na DTO

Moje pytanie brzmi, jaki jest najlepszy sposób na przetłumaczenie właściwości nawigacji modelu obiektu na jego DTO?

Poniżej jest przykładem modelu jednostki i jej DTO z projektu:

Entity Model:

public class Payment 
{ 
    public int ID { get; set; } 
    public DateTime? PaidOn { get; set; } 
    public decimal Amount { get; set; } 
    public string Reference { get; set; } 

    //Navigation Properties 
    public virtual PaymentMechanism PaymentMechanism { get; set; } 
    public virtual ICollection<Order> Orders { get; set; } 
} 

DTO:

public class PaymentDto 
{ 
    public int ID { get; set; } 
    public DateTime? PaidOn { get; set; } 
    public decimal Amount { get; set; } 
    public string Reference { get; set; } 

    //--------Navigation Properties - Object Ids-------- 
    public int PaymentMechanismId { get; set; } 
    public ICollection<int> OrderIds { get; set; } 
} 

Jak widać są bardzo podobne, z wyjątkiem właściwości nawigacji. Zmieniłem je tak, aby były przechowywane jako liczby całkowite (zamiast jednostek). Dlatego, jeśli potrzebne są elementy własności nawigacji, ich identyfikatory mogą przejść do funkcji warstwy usługi/mapowania, która pobierze elementy z bazy danych, zamapuje je do DTO i zwróci kolekcję. Czy jest to dopuszczalny sposób robienia rzeczy?

Jestem nowy w tym obszarze, więc niektóre z mojej terminologii mogą nie być całkowicie poprawne, ale mam nadzieję, że zrozumiesz, do czego zmierzam. Jeśli chcesz, bym wyjaśnił lub przedstawił dodatkowe szczegóły, daj mi znać.

Odpowiedz

12

Można załadować DTOs za pomocą projekcji:

var paymentDtos = context.Payments 
    .Where(p => p.Amount >= 1000m) // just an example filter 
    .Select(p => new PaymentDto 
    { 
     ID = p.ID, 
     PaidOn = p.PaidOn, 
     Amount = p.Amount, 
     Reference = p.Reference, 
     PaymentMechanismId = p.PaymentMechanism.ID, 
     OrderIds = p.Orders.Select(o => o.ID) 
    }) 
    .ToList(); 

Musisz zadeklarować OrderIds w DTO jako IEnumerable<int> choć nie tak ICollection<int> aby to skompilować.

Nie jestem pewien, czy ta kolekcja kluczy jest naprawdę przydatna. Jeśli chcesz, aby załadować rozkazy później można zrobić go w odrębnej metody usługi tylko w oparciu o ID z Payment, tak:

public IEnumerable<OrderDto> GetPaymentOrders(int paymentID) 
{ 
    return context.Payments 
     .Where(p => p.ID == paymentID) 
     .Select(p => p.Orders.Select(o => new OrderDto 
     { 
      ID = o.ID, 
      //etc. mapping of more Order properties 
     })) 
     .SingleOrDefault(); 
} 
+0

Dzięki za odpowiedź, cenię swój czas. Oddałbym głos, ale nie mam wystarczającej liczby przedstawicieli! Jak ten przykład odwzorowania różni się od biblioteki odwzorowania, takiej jak AutoMapper? Wiem dokładnie, co masz na myśli, mówiąc o najważniejszych kolekcjach, ale jest to sposób na zachowanie odniesienia do relacji z jednostkami. Przypuszczam, że nie zawsze jest to konieczne, ale może okazać się przydatne w przypadku niektórych DTO. –

+0

@ChrisWhite: Używanie AutoMapper zmusiłoby Cię do wczytania jednostki 'Payment' zawierającej wszystkie' Orders' najpierw z DB (ze wszystkimi kolumnami porządku), a następnie zastosowanie AutoMapper, które zignorowałoby większość załadowanych właściwości, ponieważ twoja kolekcja w dto zawiera tylko 'int'. Może to być dużo narzutów zapytania. Powyższa projekcja jest całkowicie wykonywana w bazie danych i zwraca tylko kolumny wymagane w projekcji. – Slauma