简体   繁体   English

将实体框架模型导航属性转换为DTO

[英]Translating Entity Framework model navigation properties into DTOs

I'm currently working on an n-tier web project. 我目前正在开发一个n层Web项目。 After researching into Data Transfer Objects and their benefits we decided to give this pattern a go. 在研究了数据传输对象及其优点之后,我们决定采用这种模式。 Our ASP.NET MVC website does not have direct access to the EF DbContext but instead will use DTOs to send and receive entity data. 我们的ASP.NET MVC网站无法直接访问EF DbContext,而是使用DTO发送和接收实体数据。 There will be a service/mapping layer that will convert between DTOs and entity models. 将有一个服务/映射层将在DTO和实体模型之间进行转换。

My question is, what is the best way to translate entity model navigation properties into its DTO? 我的问题是,将实体模型导航属性转换为DTO的最佳方法是什么?

Below is an example of a entity model and its DTO from the project: 以下是项目中实体模型及其DTO的示例:

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

As can be seen they are very similar except for the navigation properties. 可以看出,除导航属性外,它们非常相似。 I have changed them to hold integer Ids (of the entities) instead of the entity models. 我已将它们更改为保存整数ID(实体),而不是实体模型。 Therefore if the navigation property entities need to be obtained, their Id's can passed into a service/mapping layer function which will retrieve the entities from then database, map them to DTOs and return the collection. 因此,如果需要获取导航属性实体,则它们的Id可以传递到服务/映射层函数,该函数将从当时数据库中检索实体,将它们映射到DTO并返回集合。 Is this an acceptable way of doing things? 这是一种可接受的做事方式吗?

I am new to this area so some of my terminology might not be totally correct but hopefully you'll understand what I'm getting at. 我是这个领域的新手,所以我的一些术语可能不完全正确,但希望你能理解我所得到的。 If you need me to clarify or provide additional detail on anything, please let me know. 如果您需要我澄清或提供任何其他详细信息,请告诉我。

You can load the DTOs using a projection: 您可以使用投影加载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();

You have to declare the OrderIds in the dto as IEnumerable<int> though, not as ICollection<int> to make this compile. 您必须将dto中的OrderIds声明为IEnumerable<int> ,而不是ICollection<int>来进行此编译。

I'm not sure if this key collection is really useful. 我不确定这个密钥集合是否真的有用。 If you want to load the orders later you could do it in a separate service method just based on the ID of the Payment , like so: 如果您想稍后加载订单,您可以根据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();
}

I'm usually using Automapper for this kind of scenario. 我通常在这种情况下使用Automapper。 I would create a Dto class form my main entity and also Dto's for my navigation property entities, then let Automapper do the mapping automatically, without having to write the mapping code manually. 我将创建一个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 >();
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM