我正在这里寻找指针和信息,我将制作此 CW,因为我怀疑它没有一个正确的答案。这是针对 C# 的,因此我将在下面引用 Linq。我也为这么长的帖子道歉。让我在这里总结一下这个问题,然后是完整的问题。

概括:在 UI/BLL/DAL/DB 4 层应用程序中,如何更改用户界面以显示更多列(例如在网格中),避免通过业务逻辑层泄漏并进入数据访问层,以获取控制要显示的数据的数量(假设它已经在数据库中)。


我们假设一个具有 3(4) 层的分层应用程序:

  • 用户界面(UI)
  • 业务逻辑层(BLL)
  • 数据访问层 (DAL)
  • 数据库(DB;第4层)

在这种情况下,DAL 负责构造 SQL 语句并针对数据库执行它们,返回数据。

“正确”构造这样一个层的唯一方法是始终执行“select *”吗?对我来说这是一个很大的禁忌,但让我解释一下我为什么想知道。

假设我希望在我的 UI 中显示具有有效就业记录的所有员工。我所说的“活跃”是指从至今的就业记录包含今天(或者甚至是我可以在用户界面中设置的日期)。

在这种情况下,假设我想向所有这些人发送一封电子邮件,因此我在 BLL 中有一些代码来确保我尚未向同一个人发送电子邮件,等等。

对于 BLL,它需要最少量的数据。也许它会调用数据访问层来获取活跃员工的列表,然后调用以获取已发送的电子邮件列表。然后它加入这些并构建一个新列表。也许这可以借助数据访问层来完成,但这并不重要。

重要的是,对于业务层来说,它需要的数据确实不多。也许它只需要两个列表中每个员工的唯一标识符进行匹配,然后说“这些是那些活跃的员工的唯一标识符,您尚未向其发送电子邮件”。然后我是否要构建 DAL 代码来构建仅检索业务层需要的 SQL 语句?IE。只是“从员工那里选择 id ...”?

那么我该如何处理用户界面呢?对于用户来说,最好包含更多信息,具体取决于 为什么 我想发送电子邮件。例如,我可能想包含一些基本的联系信息,或者他们工作的部门,或者他们的经理姓名等,并不是说我至少要显示姓名和电子邮件地址信息。

UI 如何获取这些数据?我是否更改 DAL 以确保将足够的数据返回到 UI?我是否更改 BLL 以确保它为 UI 返回足够的数据?如果从 DAL 返回到 BLL 的对象或数据结构也可以发送到 UI,也许 BLL 不需要太多更改,但 UI 的要求会影响超出其应通信范围的层。如果这两个世界在不同的数据结构上运行,那么可能都必须对两者进行更改。

那么当 UI 更改时,为了通过添加更多列进一步帮助用户,我需要/应该深入到多深才能更改 UI?(假设数据已经存在于数据库中,因此不需要进行任何更改。)

提出的一项建议是使用 Linq-To-SQL 和 IQueryable,这样,如果处理什么(如数据类型)和原因(如 WHERE 子句)的 DAL 返回 IQueryable,则 BLL 可以可能会将这些返回给 UI,然后 UI 可以构造一个 Linq 查询来检索所需的数据。然后,用户界面代码可以提取它需要的列。这将起作用,因为使用 IQuerables,UI 最终将实际执行查询,然后它可以使用“select new { X, Y, Z }”来指定它需要的内容,甚至在必要时加入其他表。

这对我来说看起来很乱。UI 本身执行 SQL 代码,即使它隐藏在 Linq 前端后面。

但是,要发生这种情况,不应允许 BLL 或 DAL 关闭数据库连接,并且在 IoC 类型的世界中,DAL 服务可能会比 UI 代码希望的早一点被处理掉,因此Linq 查询可能最终会出现异常“无法访问已处置的对象”。

所以我正在寻找指点。我们离我们还有多远?你怎么处理这个问题?我认为对 UI 的更改会通过 BLL 泄漏到 DAL 中,这是一个非常糟糕的解决方案,但现在看来我们无法做得更好。

请告诉我我们有多愚蠢并证明我错了?

请注意,这是一个遗留系统。更改数据库模式还没有在几年内,因此使用本质上相当于“select *”的 ORM 对象的解决方案并不是真正的选择。我们有一些大表,我们希望避免拉出整个层列表。

有帮助吗?

解决方案

使用作为 UI 消费案例的视图模型(或数据传输对象)的概念。BLL 的工作就是获取这些对象,如果数据不完整,则请求附加数据(我们称之为模型)。然后 BLL 可以就返回哪些视图模型做出正确的决定。不要让您的模型(数据)细节渗透到 UI 中。

UI <-- (viewmodel) ---> BLL <-- (model) --> Peristence/Data layers

这种解耦可以更好地扩展您的应用程序。我认为持久性独立性很自然地从这种方法中消失,因为视图模型的构造和规范可以通过使用 linq2ql 或其他 orm 技术在 BLL 中灵活完成。

其他提示

这根本不是一个容易解决的问题。我见过很多尝试(包括您描述的 IQueryable 方法),但没有一个是完美的。不幸的是我们仍在等待完美的解决方案。在那之前,我们将不得不忍受不完美。

我完全同意 DAL 问题不应该泄漏到上层,因此绝缘 BLL 是必要的。

即使您没有能力在当前项目中重新定义数据访问技术,从持久性无知的角度思考域模型仍然会有所帮助。持久性无知的一个推论是每个域对象都是一个独立的单元,没有数据库列之类的概念。最好在此类对象中强制执行数据完整性作为不变量,但这也意味着实例化的域对象将加载其所有组成数据。这是一个非此即彼的命题,因此关键是找到一个好的领域模型,以确保每个领域对象保存(并且必须加载)“适当”的数据量。

太细粒度的对象可能会导致 DAL 接口混乱,但太粗粒度的对象可能会导致加载太多不相关的数据。

一个非常重要的练习是对领域模型的聚合进行分析和正确建模,以便它们达到适当的平衡。这本书 领域驱动设计 包含一些对聚合建模非常有启发性的分析。

在这方面可能有帮助的另一个策略是尽可能应用好莱坞原则。您描述的主要问题涉及查询,但如果您可以将焦点转移到更加面向命令的方向,您也许可以定义一些更粗粒度的接口,而这些接口不会 要求 你总是加载太多的数据。

我不知道有什么简单的解决方案可以解决这个挑战。有一些像我上面描述的技术可以帮助您解决一些问题,但最终它仍然是一门需要经验、技能和纪律的艺术。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top