从服务层返回包含多个实体的DTO对象

3
我正在开发一个使用仓储模式的 .net 多层应用程序。我的数据访问层实现了仓储模式,它有一些方法将数据返回给服务层,而服务层再将数据返回给 Web API 层。目前我编写了一些方法,可以返回客户信息或订单信息。我还需要编写能够返回客户订单信息的方法。我认为最好的地方是在服务层中编写该方法,但不确定应该如何操作。我在服务层中创建了一个 DTO 对象,它包含了客户和订单类的字段。服务层是否是编写这种逻辑的最佳位置?我认为我需要在服务层中填充 DTO 对象,并将该对象返回给呈现层。有人可以指点我吗? 实体层
 public class Customers
    {


        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Gender Gender { get; set; }
        public string Email { get; set; }

        public Address Address { get; set; }

        public int AddressId { get; set; }


        public ICollection<Orders> Orders { get; set; }

    }
    public class Orders
    {
        public int Id { get; set; }

        public DateTime? OrderDate { get; set; }
        public int? OrderNumber { get; set; }

        public Customers Customers { get; set; }

        public int CustomerId { get; set; }

        public ICollection<ProductOrder> ProductOrders { get; set; }
    }

   public class Address
    {
        public int Id { get; set; }

        public string Address1 { get; set; }

        public string Address2 { get; set; }

        public string City { get; set; }

        public State State { get; set; }

        public int StateId { get; set; }


        public ICollection<Customers> Customers { get; set; }


        public string ZipCode { get; set; }
    }

数据访问层


 public class CustomerRepository : RepositoryBase<Customers>, ICustomerRepository
    {
        public CustomerRepository(IDbFactory dbFactory)
            : base(dbFactory) { }



        public IEnumerable<Customers> GetAllCustomers()
        {
            return (from customer in this.DbContext.Customers
                    select customer).ToList();
        }

    }

    public interface ICustomerRepository : IRepository<Customers>
    {
        IEnumerable<Customers> GetAllCustomers();

    }


 public class OrderRepository : RepositoryBase<Orders>, IOrderRepository
    {
        public OrderRepository(IDbFactory dbFactory)
            : base(dbFactory) {}

        public IEnumerable<Orders> GetAllOrders()
        {
            return (from order in this.DbContext.Orders
                    select order).ToList();
        }

    }

    public interface IOrderRepository : IRepository<Orders>
    {
        IEnumerable<Orders> GetAllOrders();
    }

服务层

    public interface ICustomerService
        {
            IEnumerable<Customers> GetCustomers();
        }

        public class CustomerService : ICustomerService
        {
            private readonly ICustomerRepository _customerRepository;
            private readonly IUnitOfWork _unitOfWork;

            public CustomerService(ICustomerRepository customerRepository, IUnitOfWork unitOfWork)
            {
                this._customerRepository = customerRepository;
                this._unitOfWork = unitOfWork;
            }


            public IEnumerable<Customers> GetCustomers()
            {
                return _customerRepository.GetAll();
            }




 public interface IOrderService
        {
            IEnumerable<Orders> GetOrders();

        }

        public class OrderService : IOrderService
        {
            private readonly IOrderRepository _orderRepository;
            private readonly IUnitOfWork _unitOfWork;

            public OrderService(IOrderRepository orderRepository, IUnitOfWork unitOfWork)
            {
                this._orderRepository = orderRepository;
                this._unitOfWork = unitOfWork;
            }
           }

            public IEnumerable<Orders> GetOrders()
            {
                return _orderRepository.GetAll();
            }
           }

服务层中的Dto对象

  public class CustomerDto
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Gender { get; set; }
        public string Email { get; set; }

    }



public class OrderDto
{
    public int Id { get; set; }
    public DateTime? OrderDate { get; set; }
    public int? OrderNumber { get; set; }
}
public class CustomerOrderDto
{
    public CustomerDto Customer { get; set; }
    public OrderDto Order { get; set; }

}

在服务层中进行映射(将领域对象映射到Dto)
public class DomainToDtoMapping : Profile
{
    public override string ProfileName
    {
        get { return "DomainToDtoMapping"; }
    }

    [Obsolete]
    protected override void Configure()
    {
        CreateMap<Customers, CustomerDto>();
        CreateMap<Address, AddressDto>();
        CreateMap<Orders, OrderDto>();
        CreateMap<OrdersDetails, OrderDetailsDto>();
        CreateMap<State, StateDto>();


        CreateMap<CustomerDto, CustomerOrderDto>();
        CreateMap<AddressDto, CustomerOrderDto>();
        CreateMap<OrderDto, CustomerOrderDto>();
        CreateMap<OrderDetailsDto, CustomerOrderDto>();
        CreateMap<State, CustomerOrderDto>();

    }
}

理想情况下,您的服务层应该仅返回DTO,并且您可以使用例如Automapper将数据库实体映射到DTO。现在,您可以独立于数据库层演进服务接口,并且可以将数据库实体组合成DTO以从服务层返回。 - Ian Mercer
除了复杂性之外,问题是,使用额外的存储库层你能获得什么好处... - E-Bat
哥们,你真的需要用上 MediatR。所有这些层对象都不会对你有任何好处。把这些层合并起来吧!https://vimeo.com/131633177 - Jimmy Bogard
你还在解决这个问题吗? - Shai Cohen
2个回答

2
你考虑过实现组合模式吗?
你的CustomerOrderDto将包含一个CustomerDto和一个OrderDto类。像这样:
public class CustomerOrderDto
{
    public CustomerDto Customer {get; set;}
    public OrderDto Order {get; set;}
}

实施这种模式将带来以下优点:
  1. 任何将来对 CustomerDtoOrderDto 的更改都会自动成为 CustomerOrderDto 的一部分。
  2. 用于映射数据到 dto 类的代码可以重复使用,用于映射单个 dto 实体以及 `CustomerOrderDto'。

将实体类映射到DTO类的代码应该在您的服务层中。

将客户实体映射到客户DTO实体:

    internal static CustomerDto Map(Customer entity)
    {
        if (entity == null) throw new ArgumentNullException("entity");

        CustomerDto dto = new CustomerDto();
        try
        {
            dto.Id = entity.Id;
            dto.FirstName = entity.FirstName;
            dto.LastName = entity.LastName;
            dto.Gender = entity.Gender;
            dto.Email = entity.Email;
        }
        catch (Exception e)
        {
            string errMsg = String.Format("Map(entity). Error mapping a Customer entity to DTO. Id: {0}.", entity.Id);
            //LOG ERROR
        }

        return dto;
    }

你已经完成了检索组合 CustomerOrder 实体的存储库层吗?我看到你已经完成了 GetAllCustomers()GetAllOrders() 的存储库代码。

在将DTO发送到表示层之前,我该如何填充它? - Tom
以与您今天填充CustomerDtoOrderDto实体相同的方式,您只需将每个类发送到其相关的映射函数即可。我可能遗漏了什么,但是我在您的问题中没有看到这两个映射方法。如果您可以添加它们(或指出它们的位置,如果它们已经存在),那么我将能够更具体地回答您的问题。 - Shai Cohen
我已经更新了我的答案,并附上了一些示例映射代码。请告诉我这是否有所帮助。 - Shai Cohen
抱歉如果我有些难以理解,但是你所说的“do you need”,是指“需要”还是指“需要一个例子”? - Shai Cohen
抱歉Shai,我没有表达清楚。我的意思是,由于映射已经完成,是否需要使用automapper?我想知道的是,在从服务层返回DTO时,如何使用automapper映射。所以,例如在以下方法中,我指的是public IEnumerable<CustomerDto> GetCustomers() { } - Tom
显示剩余8条评论

0

试试这个:

public interface IOrderService
    {
        IEnumerable<CustomerOrderDto> GetOrders();
    }

 public IEnumerable<CustomerOrderDto> GetOrders()
    {
        List<CustomerOrderDto> customerOrderList = new List<CustomerOrderDto>();

        foreach (var item in customerOrderList)
        {
            CustomerOrderDto customerOrder = new CustomerOrderDto();
            //fields mapping

            customerOrderList.Add(customerOrder);
        }


        return customerOrderList;
    }

映射的最佳方法是使用linq或者this。不应该使用Automapper,因为它太慢了。


我该如何将客户、订单和地址实体映射到CustomerOrderDTO? - Tom
为每个实体创建DTO并进行映射。 - hakantopuz
我已经更新了帖子,展示了AutoMapper的使用。如果它很慢,AutoMapper有什么好处?我看到很多人推荐AutoMapper。 - Tom
我不使用automapper进行映射过程。最好的性能使用linq,但如果你想使用automapper,对于每个实体类在基类中创建。请参见:Shai Cohen的答案。 - hakantopuz
我可能在这里漏掉了什么,但是看起来你正在迭代刚实例化的customerOrderList。难道你不应该迭代一个DataReader或类似的东西吗? - Shai Cohen
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接