Search code examples
c#design-patternsdata-access-layerbusiness-logic-layer

Should Business Logic Layer access the DB/Data Access Layer?


I'm a bit confused about the relationship a BLL and DAL has. Should the BLL encapsulate the DAL via dependancy injection? Or should the BLL only act on domain objects and the DAL save/update seperately?

For example imagine (in a typical MVC app) a Cancel Order function that requires you to update the order and update the stock. Would the following be how my action would look?

public ActionResult CancelOrder (Guid orderId) {
    Order order = orderRepository.Get(orderId);
    StockItem stockItem = stockRepository.Get(order.StockItemId);

    _orderService.CancelOrder(order, stockItem);
    orderRepository.Update(order);
    orderRepository.Update(stock);
    Return View();
}

Or should it be more like the following?

public ActionResult CancelOrder (Guid orderId) {
    _orderService.CancelOrder(orderId);
    Return View();
}

(within OrderService)
public void CancelOrder(Guid orderId) {
    Order order = orderRepository.Get(orderId);
    StockItem stockItem = stockRepository.Get(order.StockItemId);

    order.Cancelled = true;
    stockItem.AmountInStock = stockItem.AmountInStock + order.Amount;
    orderRepository.Update(order);
    orderRepository.Update(stock);
}

With this option everything would then be handled by the BLL including data access. The repositories would be injected in to avoid tight coupling. Any entity retrieval would then take the form of _orderService.GetOrder(orderId); as apposed to going straight to the repository.

Excuse the crudeness of the examples as I don't have a lot of time. Does any of what I've written even remotely make sense or am I off in the wilderness?


Solution

  • Definitely not the first option, which embeds your business logic in the controller. The problem is not that the controller accesses data objects per se, but that a procedure dictated by business rules has to be followed. This procedure has no place in the controller.

    So you should either go with the second option, or possibly make Cancel a method of Order. If you have already written similar code just go with consistency.