BLL 和 DAL 之间的通信
Posted
技术标签:
【中文标题】BLL 和 DAL 之间的通信【英文标题】:Communication between BLL and DAL 【发布时间】:2011-04-26 12:52:11 【问题描述】:解决方案设置:
DAL(类库) BLL(类库) Common(类库(一些常用功能 - 枚举、日志记录、异常...)) Application1(Windows 应用程序) 应用程序2(Windows 应用程序) WebApp(Web 应用程序) ...假设我有一个 Customer 实体,即:
SQL Server 中的表 DAL 中的 CustomerDataTable BLL 中的 Customer 类 所有应用程序中的 BLL.Customer 类BLL 和 DAL 应该使用什么样的对象进行通信 - DataTable
或 List<Customer>
(例如)?在第一种情况下,BLL 逻辑应该将 Customer 对象转换为 DataTable 并将其发送到 DAL。在第二种情况下,DAL 层应该知道位于 BLL 层中的 Customer 类。但是原来的 DLL 引用的是 DAL 而不是相反...
我是否应该将所有类放入单独的程序集中,由所有其他类(Common、BusinessObjects、...)引用?在这种情况下,我可以在所有项目中使用 Customer 类。
当我知道只有一个 BLL 会使用我的 DAL 时,我是否应该费心将 DAL 和 BLL 分开。在这种情况下,我可以将它们合并到一个项目中。
PS - 我正在阅读有关 DataTables 的信息,很多人说我们根本不应该使用它们。有什么更好的选择?也许是时候让我学习一些 ORM 映射工具了 :)
【问题讨论】:
【参考方案1】:在我看来,您应该有另一个层(单独的 dll)。就像“域”一样,您会将客户等所有实体保存在哪里。 然后简单地将这个程序集包含在层次结构中的所有更高级别(DAL、BLL、UI 和其他)中。
示例架构如下所示:
(数据库) DAL BL UI
在所有级别上,您都可以访问“域”层。 DAL 应该返回 List 而不是 DataTable。在某些阶段,您可能希望在 DAL 中使用一些 OMR,例如 NHibernate,其中可能还会返回一个列表。
【讨论】:
我喜欢这个。但是有一个问题 - 如果我在模型(或域、实体)程序集中有 Customer 类,那么这个类是否也应该具有所有方法,如 GetAllCustomers、GetCustomer(int id)、...?还是模型应该只有属性,方法应该在 BLL 中? 我会让 Customer 类只作为数据实体,所以只有属性,没有像“GetAllCustomers”这样的方法。我会在 BLL 中使用该方法来使用 DAL 进行查询。 在这种情况下,我可以将部分类添加到 BLL,它从模型程序集扩展我的基类并添加方法? 不,GetAllCustomers,GetCustomer(int id) 应该放在 DAL 中(您将从数据库中获取它们,填写到像 Customer 这样的实体并返回 BLL)。在 BLL 的 99% 中,您将拥有像 GetCustomer(int id) 这样的方法,其中包含一行“return DAL.GetCustomer(id);”只是为了将业务数据传递给 UI。 “域”层仅包含业务对象。 是的,在大多数情况下。有时在模型装配中,您还可以进行一些验证。但是过滤客户或创建报告等逻辑应该在 DAL/BLL 中。一般来说,所有操作数据的东西都应该在 BLL 中【参考方案2】:如果不充分了解应用程序领域,就很难回答这个一般性问题。 我会从考虑未来最有可能发生变化的地方开始,并尝试从中找出需要灵活性的地方。
我的以下想法只是一个建议。随意考虑它们并更改/忽略您认为不相关的内容。
将 DAL 与 BLL 分开几乎总是一个好主意。数据方案是应该封装并隐藏在应用程序其余部分中的一件事,因此请将您的 DataTables、DataSets、ORM 或任何其他解决方案隐藏在 DAL 中。 BLL(和它上面的层)应该使用简单的数据类型(意思是简单的类)。我认为将这些类放在没有引用且可以在任何地方使用的 Model 类库中是个好主意。
感觉你的分层有点太多了……你真的需要 BLL 中的 Customer 类和 Application 层中的另一个吗?可能是,但我会确保并三思而后行。
根据我最近的一个项目(一个每天有 20 万独立访问者的天气网站)的经验,我们使用 link2sql 进行数据访问(主要是只读数据),并在我们的 ASP.Net MVC 应用程序中使用简单的数据类(当然作为模型/视图模型的一部分)。它工作得非常顺利,我们可以轻松更改数据方案而无需分解其他层。
关于你最后一个关于 DataTables 的问题,这些对象,如果你决定使用它们(我会投反对票),完全属于你的 DAL。它们不应该暴露给其他层,因为这会产生与该特定类的耦合。如果明天 MS 发明一个更好的课程怎么办?既然您的项目中都有大量对 DataTables、它的方法和属性的引用,您会切换吗?将您的 DAL 更改为与 NewAwsomeDataTable 类一起使用会更好,而您的应用程序的其余部分则非常无知。
希望有所帮助:)
【讨论】:
Re: ...你真的需要 BLL 中的 Customer 类和 Application 层中的另一个吗?...只有一个 Customer 类,无论它在哪里,请原谅我的误解 :)这就是我写 Application 使用 BLL.Customer 类而不仅仅是 Customer 类的原因。【参考方案3】:我会使用以下模式,因为它允许您稍后升级到不同的持久性策略。
UI/Consumer <--- (view models) --> BLL <--- Models ----> DAL/Persistence
这里视图模型在 BLL 之外使用,模型在 BLL/DAL 层之间进行通信。
在您的情况下,模型可以是 DAL 使用的任何东西——例如 DataTables,或者以后可能是 ORM 实体。 BLL 负责模型和视图模型之间的映射。
关于将类型保存在它们自己的程序集中 - 对于视图模型是这样,为了保持一致性,对于模型也是如此。
保持模型和视图模型分开可以防止持久性策略泄漏到 BLL 之外,从而允许未来对持久性进行设计更改。
这种分离的一个优点是,不同的视图模型消费者对于相同的持久性模型/实体可以有不同的视图模型。有些可能很小,属性很少,而另一些可能很大,功能丰富。它还允许您引入离线/断开连接功能,因为视图模型可以在不同时间返回,从而允许您决定数据合并策略。这也允许您成为持久性实体(例如,表格可以增长和改变形状)。因为这看起来像一个 .net 实现,所以像 AutoMapper 这样的东西将提供很多开箱即用的功能
当然,这对您的应用程序来说可能有点矫枉过正 - 但是我仍然会维护一个 BLL 映射,它只与所有 BLL 消费者讨论视图模型。这应该给你足够的解耦。
【讨论】:
【参考方案4】:将域实体推入 dal 是一种可以消除循环依赖的选项,但可能与您的意图不符。不过,这并非闻所未闻。例如 LINQ-to-SQL 生成的实体将存在于 DAL 中。
其他选项:
将它们放入一个通用的lower程序集中(但这可能会让你的 BL 相当空虚) 使用 IOC 删除/反转 BL/DAL 之间的引用这里没有唯一正确的答案。
重新数据表;我个人同意 - 我不是粉丝;)但是,它们可以成功且合理地使用。但如果我不得不使用它们,我会将它们作为实现细节保留在 DAL 中 - 而不是在此之上公开它们。
【讨论】:
以上是关于BLL 和 DAL 之间的通信的主要内容,如果未能解决你的问题,请参考以下文章
业务层 (BLL) 数据访问层 (DAL) 和 UI 之间的通用结构?
DAL/BLL 和客户端/服务器:客户端应该使用 BLL 还是 DAL 对象进行演示?或者可能是另一层(数据传输对象?)