【问题标题】:Return DTO object that contains more than one entity from the service layer从服务层返回包含多个实体的 DTO 对象
【发布时间】:2017-04-20 05:30:58
【问题描述】:

我正在使用存储库模式开发一个 .net 多层应用程序。我的实现存储库模式的数据访问层具有将数据返回到服务层层的方法,服务层层又将数据返回到 Web api 层。目前我已经编写了返回客户信息或订单信息的方法。我还需要编写将返回 CustomerOrder 信息的方法。我认为最好的地方是把它写在服务层,但不知道如何去做。我在服务层中创建了一个 DTO 对象,其中包含来自 Customer 和 Order 类的字段。是服务层最好写这个逻辑的地方。我想我必须在服务层中填充 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 从服务层返回。
  • 除了复杂性之外,问题是,通过额外的存储库层您可以获得什么...
  • 伙计,你真的需要 MediatR。所有这些图层对象对这一切都没有任何帮助。折叠这些层! vimeo.com/131633177
  • 你还在为这个问题寻找解决方案吗?

标签: c# asp.net-mvc-5 automapper repository-pattern


【解决方案1】:

您是否考虑过实施Composite Pattern

您的CustomerOrderDto 将包含一个CustomerDto 和一个OrderDto 类。像这样:

public class CustomerOrderDto
{
    public CustomerDto Customer {get; set;}
    public OrderDto Order {get; set;}
}

实施此模式将带来以下优势:

  1. 未来对CustomerDtoOrderDto 的任何更改都将自动成为CustomerOrderDto 的一部分。
  2. 将数据映射到dto 类的代码可以重复用于映射单个dto 实体以及“CustomerOrderDto”。

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

将 Customer 实体映射到 CustomerDto 实体:

    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() 的存储库代码。

【讨论】:

  • 那么你的意思是使用复合模式吗,我可以简单地在服务类中创建一个方法来返回这个 CustomerOrderDto,然后自动映射器会处理映射
  • 在发送到表示层之前如何填充这个 DTO
  • 以今天填充CustomerDtoOrderDto 实体的相同方式。您只需将每个类发送到其相关的映射函数。我可能遗漏了一些东西,但我没有在您的问题中看到这两种映射方法。如果您可以添加这些(或将它们指出给我,如果它们已经存在),我将能够更具体地回答您的问题。
  • 我所做的唯一映射是域到 dto 的映射,如我上面的帖子所示。根据您的建议,我创建了单个 dto 和复合 dto。接下来我需要做什么。您能否向我展示一个有关如何填充 customerorderdto 对象的示例。
  • 我很乐意。您能帮我提供CustomerDtoOrderDto 实体的映射功能吗?
【解决方案2】:

试试这个:

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,因为它太慢了。

【讨论】:

  • 如何在此处将 Customer、Order、Address 实体映射到 CustomerOrderDTO
  • 为每个实体创建 dto 并进行映射。
  • 我更新了帖子以展示 AutoMapper 的使用。如果 AutoMapper 速度慢,它有什么好处。我看到很多人推荐 AutoMapper。
  • 我不使用 automapper 进行映射过程。性能最好的使用 linq 但如果你想使用 automapper。对于每个实体类在基类中创建。请参阅:Shai Cohen 回答。
  • 我可能在这里遗漏了一些东西,但看起来您正在迭代您刚刚实例化的 customerOrderList。你不应该迭代DataReader 或类似的东西吗?
猜你喜欢
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 2019-08-08
  • 2013-09-08
  • 1970-01-01
  • 2012-10-01
相关资源
最近更新 更多