手动 DAL & BLL 与 ORM

Posted

技术标签:

【中文标题】手动 DAL & BLL 与 ORM【英文标题】:Manual DAL & BLL vs. ORM 【发布时间】:2010-10-28 15:20:45 【问题描述】:

哪种方法更好:1)使用第三方ORM系统或2) 手动编写DAL和BLL代码 来处理数据库?

1) 在我们的一个项目中,我们决定使用 DevExpress XPO ORM 系统,但遇到了很多小问题,浪费了我们很多时间。 amd 仍然时不时会遇到来自这个 ORM 的问题和异常,我们对这个“黑匣子”没有完全的了解和控制。

2) 在另一个项目中,我们决定从头开始编写 DAL 和 BLL。虽然这意味着要多次编写无聊的代码,但这种方法被证明更加通用和灵活:我们可以完全控制数据在数据库中的保存方式,如何从中获取数据等。所有的错误都可以以直接和简单的方式进行修复。

哪种方法通常更好?也许问题只是我们使用的 ORM(DevExpress XPO),也许其他 ORM 更好(例如 NHibernate)?

是否值得使用 ADO 整体框架

我发现 DotNetNuke CMS 使用自己的 DAL 和 BLL 代码。其他项目呢?

我想了解您的个人经历:您在项目中使用哪种方法,哪种方法更可取?

谢谢。

【问题讨论】:

【参考方案1】:

最近我决定在一个新项目中使用 Linq to SQL,我真的很喜欢它。它是轻量级的、高性能的、直观的,并且在微软(和其他人)的博客中有很多关于它的大师。

Linq to SQL 通过从数据库中创建 c# 对象的数据层来工作。 DevExpress XPO 的工作方向相反,为您的 C# 业务对象创建表。实体框架应该以任何一种方式工作。我是一名数据库专家,因此为我设计数据库的框架的想法没有多大意义,尽管我可以看到它的吸引力。

我的 Linq to SQL 项目是一个中型项目(数百甚至数千用户)。对于较小的项目,有时我只使用 SQLCommand 和 SQLConnection 对象,并直接与数据库对话,效果很好。我还使用 SQLDataSource 对象作为 CRUD 的容器,但这些看起来很笨重。

您的项目越大,DAL 就越有意义。如果它是一个 Web 应用程序,我总是使用某种 DAL,因为它们具有针对 SQL 注入攻击、更好地处理空值等的内置保护。

我争论过是否在我的项目中使用实体框架,因为微软表示这将是他们未来数据访问的首选解决方案。但是我觉得 EF 不成熟,如果你在 *** 上搜索 Entity Framework,你会发现有几个人正在为一些小而迟钝的问题而苦苦挣扎。我怀疑第 2 版会更好。

我对 nHibernate 一无所知,但有些人喜欢它并且不会使用其他任何东西。

【讨论】:

很遗憾,我对 LINQ 技术不是很熟悉,我只是很快在书中读到了有关它的一章。 LINQ to SQL 是否允许您将查询(例如“SELECT * FROM Clients”)中的一行映射到您创建的客户端类?还是只允许您使用自动生成的强类型行类? 是的,您可以使用 Linq 查询来做到这一点。它们看起来就像 SQL,只是它们映射到您的强类型类,因此您可以获得智能感知和编译器检查。 谈到 LINQ to SQL,我认为它有助于使用更少的代码更轻松地创建 DAL,这要归功于 Intellisense 等功能。但这并不能让我们免于创建 BLL 类和提供程序.我们仍然必须使用诸如“ClientsProvider.GetClientsWhoAreRich()”之类的方法创建类,它们将与 DAL 进行通信,并且在 DAL 中,我们可以使用传统的 SqlCommands 或 LINQ。但是 LINQ 并没有让我们免于创建 BLL“ClientsProvider”类。我说的不对吗? 正确。但是您不一定需要为每个可能的检索场景编写一个方法到 Clients Provider 中。如果在这些方法中返回 IQueryable 结果,则始终可以对上游的结果集运行另一个 LINQ 查询。请注意,Linq to SQL 已经提供了创建、读取、更新、删除功能。您不必编写这些查询。 我不同意。 LINQ 实际上是返回数据关系视图的路径。我可能更讨厌 C#,甚至比讨厌 Java,但 LINQ 是向前迈出的一大步。 LINQ 推动您将数据放回(嗯,主要是第一次)关系模型,并避免您必须处理的一堆 OO 杂乱无章。【参考方案2】:

也许两者都适合。您可以使用像 SubSonic 这样的产品。这样,你可以设计你的数据库,生成你的 DAL 代码(删除所有无聊的东西),使用部分类来用你自己的代码扩展它,如果你愿意,可以使用存储过程,并且通常可以完成更多的事情。

这就是我所做的。我发现这是自动化和控制之间的正确平衡。

我还要指出,我认为通过尝试不同的方法并查看最适合的方法,您走在了正确的道路上。我认为这最终是您答案的来源。

【讨论】:

【参考方案3】:

您可以尝试使用 NHibernate。由于它是开源的,因此它并不完全是一个黑匣子。它非常通用,并且有许多扩展点供您插入自己的附加或替换功能。

评论1:

NHibernate 是一个true ORM,因为它允许您在任意域模型(类)和任意数据模型(表、视图、函数和过程)之间创建映射。你告诉它你希望你的类如何映射到表,例如,这个类是映射到两个连接表还是两个类映射到同一个表,这个类属性是否映射到多对多关系等。 NHibernate 期望您的数据模型大部分被规范化,但它并不要求您的数据模型与您的域模型精确对应,也不会生成您的数据模型。

评论2:

NHibernate 的方法是允许您编写任何您喜欢的类,然后告诉 NHibernate 如何将这些类映射到表。没有要继承的特殊基类,没有所有一对多属性都必须具有的特殊列表类,等等。NHibernate 可以在没有它们的情况下发挥它的魔力。事实上,您的业务对象类根本不应该对 NHibernate 有任何依赖关系。您的业​​务对象类本身绝对没有持久性或数据库代码。

您很可能会发现您可以对 NHibernate 使用的数据访问策略进行非常细粒度的控制,以至于 NHibernate 也可能是您处理复杂情况的绝佳选择。但是,在任何给定的上下文中,您都可以随意使用 NHibernate 或不使用它(支持更自定义的 DAL 代码),因为 NHibernate 在您不需要它时会尽量不妨碍您。因此,您可以在一个 BLL 类(或方法)中使用自定义 DAL 或 DevExpress XPO,并且可以在另一个 BLL 类(或方法)中使用 NHibernate。

【讨论】:

NHibernate 允许自己设计数据库结构,还是自己创建表等?我们希望控制数据库的设计。 NHibernate 是一个 true ORM,因为它允许您在任意域模型(类)和任意数据模型(表、视图、函数、和程序)。你告诉它你希望你的类如何映射到表,例如,这个类是映射到两个连接表还是两个类映射到同一个表,这个类属性是否映射到多对多关系等。 NHibernate 期望您的数据模型大部分被规范化,但它并不要求您的数据模型与您的域模型精确对应,也不会生成您的数据模型。 您所说的 NHibernate 是一件很酷的事情。 NHibernate 是否允许您在同一应用程序中同时使用“手动 DAL / BLL”方法?这在复杂情况下可能需要,其中需要更多控制才能使用数据库。在 DexExpress XPO 中,我们发现这是一个问题。 @micha12 我更新了我的答案以回复您的最新问题。 正义,感谢您在 NHibernate 上的出色 cmet。顺便问一下,您是 NHibernate 的真正用户,还是您是开发团队的成员? :) 我希望不是后者 :)【参考方案4】:

我的个人经验是,ORM 通常完全是在浪费时间。

首先,考虑一下这背后的历史。早在 60 年代和 70 年代初,我们就有这些 DBMS 使用分层和网络模型。这些使用起来有点麻烦,因为在查询它们时,您必须处理所有检索机制:跟踪各处记录之间的链接,并处理链接不是您想要的链接的情况(例如,为您的特定查询指向错误的方向)。所以 Codd 想到了关系 DBMS 的想法:指定事物之间的关系,在查询中只说你想要的,然后让 DBMS 处理找出检索它的机制。一旦我们有几个很好的实现,数据库人员就喜出望外,每个人都转向它,整个世界都很开心。

直到 OO 人进入商业​​世界。

OO 人员发现这种阻抗不匹配:业务编程中使用的 DBMS 是关系型的,但 OO 人员在内部存储带有链接(引用)的东西,并通过找出他们必须遵循和关注的链接的详细信息来发现东西他们。是的:这本质上是分层或网络 DBMS 模型。因此,他们投入了大量(通常是巧妙的)努力,将分层/网络模型分层回关系数据库,顺便丢掉了 RDBMS 给我们的许多优势。

我的建议是学习关系模型,如果合适(经常如此)围绕它设计系统,并使用 RDBMS 的强大功能。您将避免阻抗不匹配,您通常会发现查询易于编写,并且您将避免性能问题(例如您的 ORM 层需要数百个查询来完成它应该做的事情)。

在处理查询结果时需要完成一定数量的“映射”,但如果您以正确的方式考虑它,这将非常容易:结果关系的标题映射到类,关系中的每个元组都是一个对象。根据您需要的进一步逻辑,为此定义一个实际的类可能值得,也可能不值得;只需处理从结果生成的哈希列表就很容易了。只需浏览并处理列表,做你需要做的事情,你就完成了。

【讨论】:

我当然同意 Curt 关于了解关系理论的观点。我认为像 EF 这样的工具的危险之一是程序员会让 DAL 在不了解数据库的情况下为他们完成工作,这是一个错误。 Curt,您是否有上一段中提到的两种类型的示例?我真的不喜欢我看过的 ORM。 如何映射结果取决于语言和情况。假设我们有一个查询SELECT id, name FROM some_table,其结果标题是id INTEGER, name VARCHAR(255)。一个极端是为此结果定义一类对象:class IdName public final int id; public final String name; (Java),然后有一个小例程来解析查询结果,生成这些对象的列表。换一种方式,你可能只是在 Ruby 中创建一个 Hash 对象数组,结果类似于[ :id => 17, :name => 'Fred' , :id => 23, :name => 'Joe' ]【参考方案5】:

我最近参加了一个足够大的有趣项目。我没有从一开始就加入它,我们必须支持已经实现的架构。对所有对象的数据访问是通过存储过程实现的,并在 .NET 上自动生成返回 DataTable 对象的包装方法。这种系统的开发过程非常缓慢且效率低下。我们必须为每个查询在 PL/SQL 上编写巨大的存储过程,这可以用简单的 LINQ 查询来表达。如果我们使用 ORM,我们的项目实施速度会快几倍。而且我没有看到这种架构的任何优势。

我承认,这只是一个不太成功的项目,但我得出以下结论:在拒绝使用 ORM 之前三思,你真的需要这样的灵活性和对数据库的控制吗?我认为在大多数情况下,浪费时间和金钱是不值得的。

【讨论】:

你在其他项目中使用过第三方ORM吗?如果是,那成功了吗?如果是,您使用的那些 ORM 是什么? 是的,它在 DataObjects.Net 3.9 上不是非常大的业务应用程序(两年前)。它是非常有用的 ORM,尽管它有很多限制(主要是数据库结构)和冗余特性。线下课程的概念肯定存在一些与性能相关的问题和困难,但总的来说项目是成功的。 顺便说一句,我们在那个项目中使用了 DevExpress win-forms 控件并考虑使用 XPO。它看起来像是易于使用且有用的 ORM,可用于快速应用程序开发。 我们还认为 XPO 可以帮助我们有效地访问数据库,但事实证明这是错误的:我们在 XPO 中遇到了很多轻微但非常令人沮丧的问题和异常,现在我明白了我们应该从头开始编写 DAL 和 BLL - 这将花费我们实施 XPO 的 30% 时间。【参考方案6】:

正如其他人所解释的那样,ORM 存在一个根本性的困难,即大多数情况下,没有现有的解决方案能够很好地做正确的事情。这篇博文:The Vietnam Of Computer Science 呼应了我对此的一些感受。

执行摘要类似于对象模型和关系模型之间不兼容的假设和优化。虽然早期的回报很好,但随着项目的进展,ORM 的抽象不足,而且围绕它工作的额外开销往往会抵消成功。

【讨论】:

【参考方案7】:

我已经使用Bold for Delphi 四年了。它很棒,但它不再出售,并且缺少数据绑定等一些功能。 ECO 继任者拥有这一切。 不,我不是在销售 ECO 许可证或其他东西,但我只是觉得遗憾的是,很少有人意识到 MDD(模型驱动开发)可以做什么。能够在更短的时间和更少的错误中解决更复杂的问题。这很难衡量,但我听说过 5-10 更有效的开发。当我每天使用它时,我知道这是真的。

也许一些以数据和 SQL 为中心的传统开发人员会说:

    “但是性能呢?” “我可能无法控制运行的 SQL!”

嗯……

    如果您想尽可能快地加载一个表的 10000 个实例,使用存储过程可能会更好,但大多数应用程序不这样做。 Bold 和 ECO 都使用简单的 SQL 查询来加载数据。性能高度依赖于加载一定数量数据的数据库查询次数。开发人员可以通过说这些数据属于彼此来提供帮助。尽可能高效地加载它们。

    当然可以记录实际执行的查询以发现任何性能问题。如果你真的想使用你的超优化 SQL 查询,只要它不更新数据库就没有问题。

有许多 ORM 系统可供选择,特别是如果您使用 dot.net。但老实说,做一个好的 ORM 框架是非常非常困难的。它应该集中在模型周围。如果模型发生变化,更改数据库和模型依赖的代码应该是一件容易的事。这使它易于维护。进行小而多的更改的成本非常低。许多开发人员错误地以数据库为中心并围绕它进行调整。在我看来,这不是最好的工作方式。

更多应该尝试ECO。只要模型不超过12个班级,就可以无限次免费使用。 12 节课,你可以做很多事情!

【讨论】:

【参考方案8】:

我建议您使用 Code Smith Tool 来创建 Nettiers,这对于开发人员来说是一个不错的选择。

【讨论】:

以上是关于手动 DAL & BLL 与 ORM的主要内容,如果未能解决你的问题,请参考以下文章

手动搭建简单的三层框架

bll,dal 和接口实现

Go Web App 中是不是需要有 DAL 和 BLL?

DAL 和 BLL 应通过的类型

延迟加载的 DAL 和 BLL

除了实例化 DAL 的 BLL 之外,还有啥选项允许在 n 层解决方案中进行单元测试,而不会将 DAL 暴露给 UI 或将 BLL 暴露给 DAL?