不使用ORM的N层数据库应用程序,UI如何指定数据显示的内容?

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

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


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

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

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

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

让我们说,对于我的用户界面,我希望显示所有拥有活跃就业记录的员工。 “活跃”是指今天的就业记录包含今天(或者甚至是我可以在用户界面中设定的日期)。

在这种情况下,假设我想向所有这些人发送一封电子邮件,所以我在BLL中有一些代码可以确保我还没有向同一个人发送过电子邮件,等等。

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

重要的是,对于业务层,它实际上并不需要太多数据。 也许它只需要每个员工的唯一标识符,对于两个列表,匹配,然后说“这些是活动的那些的唯一标识符,您尚未发送电子邮件到”。 然后我构造DAL代码来构造只检索业务层需要的SQL语句吗? IE浏览器。 只是“SELECT id FROM employees WHERE …”?

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

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

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

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

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

但是,为了实现这一点,不应该允许BLL或DAL关闭数据库连接,并且在IoC类型的世界中,DAL服务可能比UI代码所希望的更快地处理掉,因此Linq查询可能最终会出现“无法访问已处置对象”的exception。

所以我正在寻找指针。 我们有多远? 你是怎么处理的? 我认为对UI的更改将通过BLL泄漏到DAL是一个非常糟糕的解决方案,但是现在它看起来并不像我们可以做得更好。

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

请注意,这是一个遗留系统。 多年来,更改数据库模式的范围还不在范围内,因此使用ORM对象的解决方案实际上不等同于“select *”。 我们有一些大型表格,我们希望避免在整个图层列表中提取。

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

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

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

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

我完全同意不应允许DAL问题泄漏到上层,因此需要绝缘BLL。

即使您没有在当前项目中重新定义数据访问技术的奢侈品,仍然有助于在持久性无知方面考虑域模型。 持久性无知的一个证据就是每个域对象都是一个独立的单元,它没有像数据库列这样的东西的概念。 最好将数据集成强制实施为此类对象中的不变量,但这也意味着实例化的域对象将加载其所有组成数据。 它是一个或者一个命题,所以关键在于找到一个好的域模型,确保每个域对象保持(并且必须加载)一个“适当”的数据量。

太细粒度的对象可能会导致繁琐的DAL接口,但过于粗糙的对象可能会导致加载过多的无关数据。

一个非常重要的练习是分析并正确建模域模型的聚合,以便它们达到正确的平衡。 “ 领域驱动设计 ”一书包含了一些非常有启发性的聚合建模分析。

在这方面可能有用的另一个策略是尽可能地应用好莱坞原则。 您描述的主要问题涉及查询,但如果您可以将注意力转移到更加面向命令,那么您可以定义一些更粗粒度的接口,这些接口不需要总是加载太多数据。

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