16

我目前正在开发一个 n 层网络项目。在研究了数据传输对象及其好处之后,我们决定试一试这种模式。我们的 ASP.NET MVC 网站无法直接访问 EF DbContext,而是使用 DTO 发送和接收实体数据。将有一个服务/映射层在 DTO 和实体模型之间进行转换。

我的问题是,将实体模型导航属性转换为其 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 并返回集合。这是一种可以接受的做事方式吗?

我是这个领域的新手,所以我的一些术语可能并不完全正确,但希望你能理解我的意思。如果您需要我澄清或提供任何其他详细信息,请告诉我。

4

2 回答 2

17

您可以使用投影加载 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();

你必须OrderIds在 dto 中声明IEnumerable<int>,而不是ICollection<int>让它编译。

我不确定这个密钥集合是否真的有用。如果你想稍后加载订单,你可以在一个单独的服务方法中完成它IDPayment就像这样:

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();
}
于 2013-05-16T12:43:13.810 回答
2

我通常在这种情况下使用 Automapper。我会从我的主要实体创建一个 Dto 类,并为我的导航属性实体创建一个 Dto,然后让 Automapper 自动进行映射,而无需手动编写映射代码。

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
    public virtual PaymentMechanismDto PaymentMechanism { get; set; }
    public virtual ICollection<OrderDto> Orders { get; set; }
}

public class PaymentMechanismDto
{
//properties
}

public class OrderDto
{
//properties
}


public class MappingProfile : Profile
{
        public MappingProfile()
        {
            Mapper.CreateMap< Payment, PaymentDto >();
            Mapper.CreateMap< PaymentMechanism, PaymentMechanismDto >();
            Mapper.CreateMap< Order, OrderDto >();
        }
}
于 2018-08-24T11:15:10.113 回答