业务逻辑层应该访问数据库/数据访问层吗?

Posted

技术标签:

【中文标题】业务逻辑层应该访问数据库/数据访问层吗?【英文标题】:Should Business Logic Layer access the DB/Data Access Layer? 【发布时间】:2012-08-30 00:39:25 【问题描述】:

我对 BLL 和 DAL 的关系有点困惑。 BLL 是否应该通过依赖注入封装 DAL?还是应该 BLL 只作用于域对象和 DAL 分别保存/更新?

例如(在典型的 MVC 应用程序中)想象一个取消订单功能,该功能要求您更新订单并更新库存。以下是我的操作的样子吗?

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

还是应该更像下面这样?

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

使用此选项后,所有事情都将由 BLL 处理,包括数据访问。将注入存储库以避免紧密耦合。然后,任何实体检索都将采用_orderService.GetOrder(orderId); 的形式,而不是直接进入存储库。

请原谅这些例子的粗俗,因为我没有太多时间。我写的任何东西都有意义吗?还是我在荒野中?

【问题讨论】:

【参考方案1】:

BLL 应该作用于您为应用程序创建的业务对象。理想情况下,它不应该知道数据库和相关操作。如果您希望保持松散耦合,请使用依赖注入从 DAL 调用方法。

【讨论】:

【参考方案2】:

绝对不是第一个选项,它将您的业务逻辑嵌入到控制器中。问题不在于控制器访问数据对象本身,而在于必须遵循由业务规则规定的程序。此过程在控制器中没有位置。

所以你应该选择第二个选项,或者可能让Cancel 成为Order 的方法。如果您已经编写过类似的代码,请保持一致性。

【讨论】:

第二个选项是我的偏好。关于在 Order 类中放置一个 Cancel 方法,这会对数据库执行操作吗?在我的职业生涯中,我一直认为域对象不应该关心数据访问。还是你的意思是别的? @David:不,我就是这个意思。在某些设计中,域对象了解它们所属的数据存储。如果不是你,请忽略。 :) +1。我倾向于将涉及多个实体的逻辑放在服务中,以将持久性(存储库)排除在实体之外。【参考方案3】:

考虑关注点分离,Controller 来自 MVC 模式,即 PRESENTATION 模式,因此控制器应该包含支持表示层的表示逻辑,而不是业务逻辑。

一致认为业务逻辑应该在域实体中,但也有一些应用程序逻辑在存储库之间扮演协调者的角色,这就是服务层在路上失败的原因。

因此,选项 2 应该是你的方式。

【讨论】:

【参考方案4】:

你真的在这里问了两个问题:

Controller 和业务层应该是什么?

=> 我倾向于认为您的第一个 sn-p 中的代码是应用层服务的正确责任级别(因此,如果您承认可以将两者相提并论,那么对于控制器来说,这有很多讨论关于这些时间)。从存储库中获取Order 并在取消操作后保存它看起来不像纯粹的业务逻辑。它更多地与周围的事务/工作单元以及您的用例的管道有关。

我只想更改一件事 - 尝试一次性将更改保存到受您的交易影响的所有实体。如果您必须手动更新可能在操作结束时更改的每个实体,这将是一个很大的痛苦,并且会不必要地污染控制器。创建一个工作单元系统(或使用现有的实现),它将一次保留所有更改并删除存储库中的所有 Update() 方法。

除此之外,正如 Jon 所建议的那样,我还认为包含 Cancel() 方法的丰富 Order 域对象比服务更可取 - 但这是另一个争论。

BLL和DAL应该有什么样的关系?

=> BLL 不应该与 DAL 紧密耦合,并且作为最中心的层,它不应该直接引用外层。通过这种方式,您可以轻松地在另一个应用程序中重用您的 BLL,使用另一个 DAL 等。

但是,有时某些业务对象需要直接访问它们还没有引用的其他对象,这基本上意味着从数据库中获取它们。换句话说,BLL 中的某些操作需要与存储库通信。因此,我总是将存储库 接口 放在 BLL 中,但它们的 实现 驻留在 DAL 中,并在运行时注入到 BLL 中。

因此,BLL 只是松散地耦合到 DAL。它仍然不了解持久性,因为它只操作看起来像中性对象集合的外观(存储库),并且不知道数据是如何存储、水合等的。

【讨论】:

我认为我肯定喜欢轻度耦合的 BLL 和 DAL。我想老实说,我问的问题是“移植到桌面应用程序有多容易?”并且使用选项 1,业务规则开始渗透到有效的前端。我想进入我的 MVC 应用程序只是服务层的瘦客户端消费者的阶段。同意 Transactional 评论,我经常使用 NHibernate,我按照建议将所有内容都包装在 Transactions 中。 “业务规则开始渗透到有效的前端” - 我同意,但这些是特定于应用程序的业务规则,而不是特定于域的 业务规则。取消订单导致库存增加相应数量的规则是特定于域的,无论应用程序如何,它都不会改变。相反,什么告诉您在桌面或移动应用程序中,订单需要在取消后立即保存(特定于应用程序)?如果用例略有不同,什么告诉您执行操作的顺序和时间不会改变? 因此,您可能希望您的控制器成为一个只有 UI 问题且没有应用程序业务规则的薄层。但 IMO 更好的解决方案是创建一个额外的应用程序服务层,而不是将这些特定于应用程序的业务规则直接放在域(或 BLL)中。

以上是关于业务逻辑层应该访问数据库/数据访问层吗?的主要内容,如果未能解决你的问题,请参考以下文章

将数据访问逻辑从业务层移至数据访问层

java开发时为啥要dao和service都是model层吗?

Java Web 开发时的 MVC 模型和软件的3层架构(表现层,业务逻辑层,数据访问层)都有哪些区别和联系?

在单独的数据访问和业务逻辑层中,我可以在业务层中使用实体框架类吗?

java三层架构:数据访问层业务逻辑层表现层

从数据访问层拉出业务逻辑