2013-05-16 54 views
7

我目前正在研究一個n層web項目。在研究了數據傳輸對象及其好處後,我們決定放棄這種模式。我們的ASP.NET MVC網站沒有直接訪問EF DbContext,而是使用DTO發送和接收實體數據。將有一個服務/映射層將在DTO和實體模型之間進行轉換。將實體框架模型導航屬性轉換爲DTOs

我的問題是,將實體模型導航屬性轉換爲其DTO的最佳方式是什麼?

下面是一個實體模型的例子,從項目的DTO:

實體模型:

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

可以看出除導航屬性外,它們非常相似。我已經改變它們來保存(實體的)整數ID而不是實體模型。因此,如果需要獲取導航屬性實體,則它們的Id可以傳遞到服務/映射層功能中,該功能將從當時的數據庫中檢索實體,將它們映射到DTO並返回集合。這是一種可以接受的做事方式嗎?

我是這個領域的新手,所以我的一些術語可能不完全正確,但希望您能理解我所掌握的內容。如果您需要我澄清或提供任何其他細節,請告訴我。

回答

12

您可以使用投影加載的DTO:

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(); 

你必須在DTO申報OrderIdsIEnumerable<int>雖然不是ICollection<int>使這個編譯。

我不確定這個密鑰集合是否真的有用。如果你想以後加載命令,你可以做到這一點,在短短基礎上,PaymentID一個單獨的服務方法,像這樣:

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

謝謝您的回答,我很欣賞你的時間。我會給你一個投票,但我沒有足夠的代表! 這個投影示例與AutoMapper這樣的映射庫有什麼不同? 我確切地知道你對密鑰集合的含義,但它是保持對實體關係的引用的一種方式。我想這並不總是必要的,但對於一些DTO來說它可能會有用。 –

+0

@ChrisWhite:使用AutoMapper將迫使您首先從數據庫(包括所有的訂單列)加載包括所有訂單的「Payment」實體,然後應用AutoMapper,該AutoMapper會忽略大多數加載的屬性,因爲您的集合在dto只包含一個'int'。這可能會造成很多查詢開銷。上面的投影完全在數據庫中執行,並只返回投影中請求的列。 – Slauma