O/R 映射器 - 好或坏

Posted

技术标签:

【中文标题】O/R 映射器 - 好或坏【英文标题】:O/R Mappers - Good or bad 【发布时间】:2010-11-18 00:35:15 【问题描述】:

我现在真的在使用 O/R 映射器还是仅仅坚持传统的数据访问之间纠结。出于某种原因,每次我提出 O/R 映射器时,其他开发人员都会畏缩并谈论性能问题或它们总体上是如何糟糕的。我在这里想念什么?我正在研究 LINQ to SQL 和 Microsoft Entity Framework。这些说法有任何依据吗?如果我想使用 O/R 映射器,我必须在哪些方面做出妥协。谢谢。

【问题讨论】:

我喜欢那些出于“性能原因”花费 80% 的项目来完善手卷 dal 然后向最终用户吐出 100k 臃肿视图状态的开发人员......优先级 这应该是社区维基吗? 这个问题已经被问过很多次了。只需搜索“ORM”,您就会找到一堆。 【参考方案1】:

我看到很多 OR 映射器的问题是你得到臃肿的域对象,它们通常与你的数据访问框架的其余部分高度耦合。我们的开发人员也对此感到畏缩 :) 将这些对象移植到另一种数据访问技术更加困难。如果你使用 L2S,你可以看看生成的代码。它看起来像一团糟。 NHibernate 可能是这方面最好的之一。如果您的设计正确,您的实体将完全不知道您的数据访问层。

【讨论】:

DTO 实际上是您的通行证。而且,是的,他们的缺点之一是他们创造的阶级爆炸。【参考方案2】:

我第一次接触 ORM 映射和数据访问层是通过阅读 Rockford Lhotka 的书《C# 业务对象》。他花了数年时间研究 DAL 的框架。虽然他开箱即用的框架相当臃肿,而且在某些情况下过于矫枉过正,但他有一些很棒的想法。我强烈推荐这本书给任何关注 ORM 映射器的人。我受到他的书的影响,足以将他的许多想法带走,并将它们构建到我自己的框架和代码生成中。

【讨论】:

【参考方案3】:

乍一看,这似乎是一个无关紧要的答案,但是:我的兴趣之一是二战时期的战斗机。所有的战斗国家(美国、英国、德国、苏联、日本等)在战争期间都建造了一堆不同的战斗机。其中一些使用星形发动机(P47、海盗船、FW-190、零式);一些使用直列液冷发动机(Bf-109、Mustang、Yak-7、Spitfire);有些使用两个引擎而不是一个(P38,Do-335)。有的用机枪,有的用大炮,有的两者都用。如果你能想象的话,有些甚至是用胶合板制成的。

最后,它们都飞得非常快,而且在一个称职、经验丰富的飞行员手中,他们会在心跳中击落你的菜鸟。我不认为有很多飞行员飞来飞去想“哦,那个白痴正在用星形发动机飞行——我根本不用担心他”。每个人都明白,实现最终目标的方法有很多种,每种方法都有其特定的优点和缺点,视情况而定。

ORM 和传统数据访问之间的争论就是这样,任何程序员都应该能够胜任这两种方法,并选择适合手头工作的选项。

【讨论】:

投了反对票,因为“为正确的工作选择正确的工具”是任何编程问题的常见和通用答案。相反,一个更好的答案将阐明 ORM 何时合适或不合适的情况。我会第二次投反对票,因为一旦考虑到细微之处,使用物理类比来描述程序架构选择总是会失败。飞行员培训时间、飞机维护成本、资源使用情况? @jfar:我的观点比你显然采取的方式更笼统——那些说“ORM 很棒而另一种方式完全是废话”(反之亦然)的人只是愚蠢。不要说“没人这么说”,因为人们在 SO 上一直都在说这样的话。至于在考虑细节时软件崩溃的物理类比,我不想说“duh”,所以我不会。【参考方案4】:

我为这个决定苦苦挣扎了很长时间。我想我之所以犹豫,主要有两个原因。首先,O/R 映射器代表了对应用程序关键部分发生的事情缺乏控制,其次,因为很多时候我对解决方案感到失望,这些解决方案在 90% 的情况下很棒,但在最后的情况下却很糟糕10%。当然,一切都适用于 select * from authors,但是当你提高复杂性并拥有一个大容量、关键的系统并且你的职业生涯即将到来时,你会觉得你需要完全控制来调整每个查询模式和字节在电线上。大多数开发人员,包括我,在工具第一次失败时会感到沮丧,我们无法做我们需要做的事情,或者我们的需求偏离了工具支持的既定模式。我可能会因为提到工具中的特定缺陷而受到抨击,所以我就这样说吧。

幸运的是,Anderson Imes 最终说服我尝试使用CodeSmith 和netTiers template。 (不,我不为他们工作。)在使用了一年多之后,我不敢相信我们没有早点这样做。我的团队使用 Visual Studio DB Pro,在每次签入时,我们的持续集成构建都会删除一组新的数据访问层程序集。这会自动处理所有常见的、低风险的东西,但我们仍然可以为棘手的部分编写自定义存储过程,并将它们作为方法包含在生成的类中,我们也可以为生成的代码自定义模板。我强烈推荐这种方法。可能还有其他工具也可以实现这种级别的控制,并且有一个名为 PLINQO 的较新 CodeSmith 模板在后台使用 LINQ to SQL。我们还没有研究过(没有必要),但这种整体方法有很多优点。

杰瑞

【讨论】:

【参考方案5】:

对此没有简单的答案,因为每个 ORM 提供者都有自己特定的优点和缺点。一些 ORM 解决方案比其他解决方案更灵活。开发人员有责任在使用之前了解这些内容。

但是,以 LinqToSql 为例 - 如果您确定不需要从 SQL Server 切换,那么这可以解决 ORM 映射器中的许多常见问题。它允许您轻松添加存储过程(作为静态方法),因此您不仅限于生成的 SQL。它使用延迟执行,因此您可以有效地将查询链接在一起。它使用部分类允许您轻松地将自定义逻辑添加到生成的类中,而无需担心重新生成它们时会发生什么。也没有什么能阻止您使用 LINQ 创建自己的抽象 DAL - 它只是加快了进程。但主要的是,它减轻了创建基本 CRUD 层所需的乏味和时间。

但也有缺点。您的表和类之间将存在紧密耦合,性能会略有下降,您可能偶尔会生成效率不如预期的查询。而且您与 SQL Server 相关联(尽管其他一些 ORM 技术与数据库无关)。

正如我所说,主要是在将颜色固定到特定方法之前了解利弊。

【讨论】:

大多数其他 O/RM 工具允许映射到存储过程同样容易。仅举几例:(N)Hibernate 和 EntityFramework。微软也停止了 Linq2Sql 的工作,所以我们几乎坚持当前的实现...... 停止在 Linq2Sql 上工作? damieng.com/blog/2009/06/01/linq-to-sql-changes-in-net-40【参考方案6】:

O/RM 工具旨在在大多数情况下都表现出色。它将为您缓存实体,它将批量执行查询,它具有对对象的非常低级别的优化访问,这比手动为属性分配值要快得多,它们为您提供了一种非常简单的方法来合并面向方面编程的变体,使用拦截器等现代技术,它将为您管理实体状态并帮助解决冲突等等。

现在,这种方法的缺点通常在于对事物在非常低的层次上如何运作缺乏了解。最经典的问题是“SELECT N+1”(link)。

我已经使用 NHibernate 2.5 年了,而且我几乎每天都在发现一些关于它的新东西...

【讨论】:

【参考方案7】:

很好。在大多数情况下。

在大多数情况下,使用 ORM 的生产力优势将超过失去对数据访问方式的控制。

没有多少人会避免使用 C#,以便编程是 MSIL 或 Assembly,尽管这会给他们更多的控制权。

【讨论】:

+1 因为关键字:生产力。我在 mysql 中实现了一种带有复杂数据库的 CRM 系统。我无法想象每次需求发生变化时都必须手动进行所有映射......而且它发生了 50 次。【参考方案8】:

这真的取决于情况。

我从一家使用经过调整的 ORM 的公司转到一家不使用 ORM 并一直编写 SQL 查询的公司。当我问及使用 ORM 来简化代码时,我一脸茫​​然,然后是所有的负面:

它的膨胀 您无法很好地控制查询并执行不必要的查询 表映射有重物 它不是枯燥的代码,因为你必须重复自己

开着

嗯,在那里工作了几个星期后,我注意到:

我们有几个查询几乎完全相同,而且很多时候如果有错误,只有少数会得到修复 我们最终会多次读取一个表,而不是缓存常见的表查询。 我们到处都在重复我们自己 我们有几个级别的技能水平,所以有些查询的编写效率不是最高的。

在我指出大部分内容后,他们写了一个“DBO”,因为他们不想称它为 ORM。他们决定从头开始写一个,而不是修改一个。

另外,我觉得很多争论来自对 ORM 的无知。我见过的每个 ORM 都允许自定义查询,即使遵循 ORM 的约定,您也可以编写非常复杂和详细的查询,并且通常更具人类可读性。此外,它们往往非常干燥,你给他们你的架构,他们会解决剩下的问题,直到关系映射。

现代 ORM 有很多工具可以帮助您,例如迁移脚本、访问相同对象的多种 DB 类型,因此您可以利用 NOSQL 和 SQL DB 的优势。但是如果你要使用一个,你必须为你的项目选择正确的 ORM。

【讨论】:

以上是关于O/R 映射器 - 好或坏的主要内容,如果未能解决你的问题,请参考以下文章

可以自动更新数据库模式的 O/R 映射器?

如果映射器在中途失败并且 Hadoop 重试该映射器,自定义计数器会发生啥

MyBatis 生成器 - 生成映射器实现

根据映射器代码中的某些逻辑,将映射器中的一些数据(行)写入单独的目录

纯 Java MyBatis 映射器?

keycloak 客户端协议映射器(脚本映射器)将请求标头添加到令牌中