3
votes

I am developing an .net multi tier application using repository pattern. My data access layer which implements the repository pattern has methods that return the data to Service layer layer which in turn returns data to the web api layer. Currently I have written methods that will return either Customer information or Order information. I need to also write methods that will return CustomerOrder information. I think the best place is to write it in the service layer but not sure how to go about it. I have created a DTO object in the service layer which contains fields from both the Customer and Order class. Is the service layer the best place to write this logic. I think I would have to populate the Dto object in the service layer and return that object to the presentation layer. Could somebody show me the way.

Entity layer

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

DataAccess Layer

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

Service layer

    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 object in the service layer

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

}

Mapping (Domain objects to Dto) in the service Layer

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

    }
}
2
Ideally, your service layer would return only DTOs and you would use, say, Automapper to map Database entities to DTOs. Now you can evolve the service interface independently from the database layer and can combine database entities into DTOs to return from the service layer.Ian Mercer
Apart from complexity, the question is, what do you gain with an additional repositorylayer...E-Bat
Man, you really need MediatR. All those layer objects aren't doing you any favors with all this. Collapse those layers! vimeo.com/131633177Jimmy Bogard
Are you still working on a solution to this?Shai Cohen

2 Answers

2
votes

Have you considered implementing the Composite Pattern?

Your CustomerOrderDto would contain a CustomerDto and an OrderDto class. Like so:

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

Implementing this pattern would give the following advantages:

  1. Any future changes to the CustomerDto or OrderDto would automatically be part of the CustomerOrderDto.
  2. The code for mapping data to the dto classes can be reused for mapping a single dto entity as well as the `CustomerOrderDto'.

The code for mapping the Entity classes to the DTO classes should be in your service layer.

Mapping the Customer entity to the CustomerDto entity:

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

Have you completed the repository layer for retrieving the Composite CustomerOrder entities? I see you have the completed repository code for GetAllCustomers() and GetAllOrders().

0
votes

Try this:

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

The best method for mapping is linq or this.You shouldn't use Automapper because it's so slow.