68

我希望社区了解我对 Linq to Sql 和其他 ORM 映射器的一些想法。

我喜欢 Linq to Sql 以及用您的本地开发语言表达数据访问逻辑(或一般的 CRUD 操作)的想法,而不是必须处理 C# 和 SQL 之间的“阻抗不匹配”。例如,要为业务层返回与 ObjectDataSource 兼容的 Event 实例列表,我们使用:

return db.Events.Select(c => new EventData() { EventID = c.EventID, Title = c.Title })

如果我要使用旧的 SQL-to-C# 结构来实现它,我必须创建一个 Command 类,添加 EventID 参数(使用字符串来描述“@EventID”参数),将 SQL 查询字符串添加到命令类,执行命令,然后使用 (cast-type)nwReader["FieldName"] 提取每个返回的字段值并将其分配给我的 EventData 类的新创建实例的成员 (yuck)。

所以,就是人们喜欢 Linq/SubSonic/等的原因。并且我同意。

然而,从更大的角度来看,我看到了许多错误的事情。我的感觉是微软也看到了一些错误,这就是为什么他们正在杀死 Linq to SQL并试图将人们转移到 Linq to Entities。只是,我认为微软正在加倍下注。

那么,有什么问题呢?

问题是有些架构宇航员,尤其是在微软,他们看到 Linq to Sql 并意识到它不是一个真正的数据管理工具:仍然有很多事情你不能轻松地在 C# 中轻松完成,他们的目标是修复它. 您可以在 Linq to Entities 背后的雄心壮志、关于 Linq革命性的 博客文章甚至是LinqPad 挑战中看到这一点。

问题在于它假设 SQL 是问题所在。也就是说,为了减少轻微的不适(SQL 和 C# 之间的阻抗不匹配),微软提出了相当于太空服(完全隔离),而创可贴(Linq to SQL 或类似的东西)就可以了。

据我所知,开发人员非常聪明,能够掌握关系模型,然后在他们的开发工作中智能地应用它。事实上,我会更进一步地说,Linq to SQL、SubSonic 等已经太复杂了:学习曲线与掌握 SQL 本身并没有太大区别。由于在可预见的未来,开发人员必须掌握 SQL 和关系模型,我们现在面临学习两种查询/CRUD 语言。更糟糕的是,Linq 通常很难测试(你没有查询窗口),将我们从我们正在做的实际工作中移除了一层(它生成 SQL),并且对 SQL 结构(充其量)非常笨拙的支持,例如日期处理(例如 DateDiff)、“Having”甚至“Group By”。

什么是替代方案?就个人而言,我不需要像 Linq to Entities 这样的数据访问模型。我更喜欢简单地在 Visual Studio 中弹出一个窗口,输入并验证我的 SQL,然后按一个按钮生成或补充一个 C# 类来封装调用。既然您已经了解 SQL,您是否更愿意只输入如下内容:

Select EventID, Title From Events Where Location=@Location

并最终得到一个 EventData 类,A) 包含 EventID 和 Title 字段作为属性,B) 有一个工厂方法,该方法将“Location”字符串作为参数并生成 List<EventData>? 您必须仔细考虑对象模型(上面的示例显然没有处理该问题),但在消除阻抗不匹配的同时仍然使用 SQL 的基本方法对我很有吸引力。

问题是:我错了吗?微软是否应该重写 SQL 基础架构,以便您不必再学习 SQL/关系数据管理? 他们能以这种方式重写 SQL 基础架构吗?还是您认为在 SQL 之上的一个非常薄的层来消除设置参数和访问数据字段的痛苦就足够了?

更新我想将两个链接推广到顶部,因为我认为它们抓住了我所追求的重要方面。首先,CodeMonkey 指出了一篇题为“计算机科学的越南”的文章。 开始需要一段时间,但读起来非常有趣。其次,AnSGri 指出了 Joel Spolsky 最杰出的作品之一:泄漏抽象法则。它不完全是主题,但它很接近并且是一本很好的读物。

更新 2:我已经给 ocdecio 提供了“答案”,尽管这里有很多很好的答案,而“正确”答案的选择纯粹是主观的。在这种情况下,他的回答与我认为在当前技术状态下真正的最佳实践相一致。然而,这是一个我完全期望发展的领域,所以事情很可能会发生变化。我要感谢所有做出贡献的人,我投票给了我认为给出了深思熟虑的答案的每个人。

4

24 回答 24

45

让我先说我是一个彻头彻尾的数据库专家。

作为一个粗略的概括:开发人员不知道 SQL。开发人员并不真正了解 SQL。他们可以写,他们可以设计表格,但这让他们感到恶心。当必要的查询不仅仅是一个简单的连接时,他们往往会做一些愚蠢的事情。不是因为开发人员很愚蠢——因为他们不会被打扰。他们喜欢生活在一个只需要处理一个概念空间的世界里;从对象到表再返回是上下文切换,他们不喜欢为此付出代价。

这并不意味着它们是坏的或错误的。这意味着有改进的机会。如果您的客户(在这种情况下,是使用您的框架的开发人员)不喜欢 SQL 和表 - 给他们一个抽象层,让他们无需处理底层混乱即可摆脱困境。

垃圾收集/自动内存管理大受欢迎的逻辑相同。是的,开发人员可以处理它;是的,没有它,他们可以编写更好优化的代码;但不必处理它会让他们更快乐,更有效率。

于 2009-01-19T19:37:20.647 回答
36

我认为 ORM 的流行是由开发数据层的开发人员在一个又一个应用程序中一遍又一遍地编写相同的 CRUD 代码而产生的。ORM 只是另一种工具/技术,它可以让开发人员花费更少的时间一遍又一遍地编写相同的 SQL 语句,而是专注于应用程序的逻辑(希望如此)。

于 2009-01-19T19:28:31.787 回答
18

至少 6 年来,我一直在使用自己的 ORM,它基于一个非常简单的概念:投影。每个表都被投影到一个类中,并根据类定义动态生成 SQL。它仍然需要我了解 SQL,但它可以处理 90% 的简单 CRUD,而且我不必管理连接等 - 它适用于主要的数据库供应商。

我对我所拥有的感到满意,并且没有发现任何值得放弃的东西。

于 2009-01-19T19:35:45.143 回答
12

恕我直言,OR/M 不仅仅是关于“抽象 SQL”或隐藏 SQL,或启用多 DBMS 支持。

它使您能够将更多精力放在您的问题域上,因为您不必花费更少的时间编写无聊的 CRUD SQL 查询。另一方面,如果您使用了良好的 OR/M,则此 OR/M 应该使您能够编写 SQL 查询(如果这似乎是必要的)。

如果使用得当,OR/M 可以成为一个强大的工具;它可以处理延迟加载、多态查询/关联......
不要误会我的意思;纯 SQL 没有任何问题,但是,如果您必须小心地将(经过深思熟虑和规范化的)关系模型转换为富有表现力的 OO/域模型,那么我认为您正在花费大量时间进行管道工程。

使用 OR/M 也不意味着您(作为开发人员)不应该了解 SQL。相反是真实的恕我直言。
了解 SQL 并知道如何编写高效的 SQL 查询,这将使您能够正确使用 OR/M。

我还必须承认,我在写这篇文章时考虑到了 NHibernate。这是我正在使用 atm 的 OR/M,我还没有使用 Linq to SQL 或 Linq to entity。

于 2009-01-19T22:23:58.283 回答
10

Linq 的设计和 linq to entity 框架当然可以用作 orm 工具,但主要的想法是它将用作查询任何数据源的通用 api,而不仅仅是 RDBMS 的。

我记得读过 linq,虽然显然设计时考虑了 SQL,但它旨在成为任何数据存储的查询语言。您可以为 SQL 编写 linq 查询,但理论上您也可以编写针对 ldap、文件系统、交换、Web 服务、无限期的 linq 查询。您不能将 SQL 用于这些程序。

您还需要为几乎每个数据存储学习不同的 API。Linq 为每个人提供了创建数据访问 API 的共同目标。

这个愿景是否有效还有待观察,但这就是想法。我认为随着我们希望系统越来越多地互操作,我们可能会发现 l2e 有一些非常好的用途。

如果我能再次找到它们,我会添加一些参考。

http://laribee.com/blog/2007/03/17/linq-to-entities-vs-nhibernate/

于 2009-01-19T21:18:40.990 回答
9

我同意 100%。这在很大程度上是因为程序编码技能和 SQL 编码技能非常不同。而这一事实并未得到广泛承认。因此,在实现这一目标之前,程序员会寻找使他们的技能从一个领域转移到另一个领域的方法。

它不起作用。

您只需要学习如何相移:学习如何根据您正在处理的领域以不同的方式思考您的代码。

有没有其他人注意到查询从 SQL 映射到 LINQ 时变得多么复杂和冗长?就像,在所有在线示例中?

于 2009-01-19T19:37:53.953 回答
9

你应该停止担心,学会爱上 ORM。诸如此类的抽象将帮助我们集中我们的技能并在该领域取得进步。

仍然有足够的空间来利用您获得的功能技能并将它们应用到应用程序层。这实际上是 LINQ to SQL 优于其他 ORM 的优势之一。

我只能同意其他许多评论。节省的时间,您可以专注于改进您的领域模型并制作更好的应用程序。而且,一旦您确定了瓶颈,就可以使用它来创建优化的 SQL。

可能不会立即明显的是,ORM 带有许多非常好的特性。有助于避免反复加载项目的身份映射,延迟加载可帮助您以更少的管道表达域,工作单元可帮助您跟踪更改并优化数据库写入。

于 2009-01-19T19:54:53.107 回答
7

正如 Dmitriy指出的那样,开发人员不了解 SQL。更准确地说,大多数人知道SQL,但不理解它,绝对不喜欢它,所以他们倾向于寻找灵丹妙药,创造对 Linq 之类的东西的需求,以制造他们不知道的错觉(嗯,抽象)不要使用与他们心爱的课程不同的任何东西。

这是非常糟糕的,因为泄漏抽象定律总是成立的。

一些 ORM 解决方案确实很好(例如 JPA/Hibernate),并不是因为使用它们您不必担心 SQL。事实上,要有效地使用 JPA,您通常需要对 DB 有非常深入的了解,尤其是查询能力。好处是它们让机器完成无聊的工作,以至于它从头开始自动生成整个数据库。

我认为,Linq to SQL 并不能解决真正的问题。这是一种其他的演示,仅此而已。这可能很好,尽管它使已经很复杂的语言过于复杂。另一方面,Linq to Objects 是一个非常有趣的概念,因为它是一种 sql 查询集合。

于 2009-01-20T05:14:41.510 回答
6

历史的角度。

当科德等人。人。最初是在研究关系数据库的理论和实现,一个完全独立的问题是“我们如何查询这些东西”?提出了许多策略和语法,具有各种优点和缺点。其中一个候选者是 SQL(显然是其最早的形式)。另一个是 QBE(按示例查询)。我相信另一个叫“quel”;还有其他几个。SQL 当然没有成为主导,因为它被认为优于所有其他方法。不幸的是,其他人几乎消失了,我们所有人都很贫穷(因为它们可以同时用于相同的数据。)

如果微软有一个很好的故事,他们正在复兴其中一种其他语言,或者发明了一个有价值的补充,那么我认为我们最好听听。但到目前为止,我所看到的只是另一个“统治他们所有人的戒指”。

SQL 背后有大量的思考和严谨,以及大量经过时间证明的耐用性。微软有一定的历史,相信他们公认的顶级开发组织可以超越我们其他人,包括我们集体的机构记忆。它似乎并不经常以这种方式工作。只要我们绑定到关系数据存储,我们就应该三思而后行,超集抽象范式使我们远离裸机,并承诺提供相同或更好的性能。

于 2009-01-19T19:51:52.223 回答
5

作为我自己的一个 ORM 项目的作者,我不得不承认我对这样一个问题的回答可能有点偏颇。在阅读问题之前,我已经对答案产生了一些自己的想法,所以我已经有点锚定了。

我会说,我开发 ORM 的原因不是因为 SQL 和命令式编程之间的“阻抗不匹配”,而仅仅是为了与数据库平台无关。必须编写更多代码来管理持久性的前一个问题是一个小障碍,如果您只与一个数据库供应商合作,则很容易解决。成为数据库平台不可知论是一个更具挑战性的问题,假设您像我一样计划向其他人出售软件(并且不仅仅是在内部使用它),那么 imo 对您的业务盈利能力的影响要大得多。

几年前,当我开始使用我的 ORM 工具时,这个概念在我喜欢的语言中是不切实际的,与我交谈的大多数人都不明白我为什么要这样做,社区中一些受人尊敬的声音与书面文章一样多在贸易杂志上说我已经做过的不仅不可能而且不受欢迎。给出了一些相同的原因——它太复杂了,它受到限制并且增加了开销。今天,同一个社区至少拥有三种流行的数据库抽象工具(尽管关于 ORM 一词的定义存在一些争论)。我之所以提到这一点,是因为当我开始研究这些工具时,最初的反对意见比现在要重要得多。近年来,硬件和软件的基础技术发生了变化,从长远来看,这些工具更加实用。我的倾向是尝试从长远角度看待软件,并致力于解决可能还不太实用但很快就会变得实用的解决方案。因此,鉴于我不会将 LINQ to Entities 视为某些问题的良好解决方案。

我也倾向于选择更多而不是更少。因此,虽然我可能支持开发 LINQ to Entities 背后的想法,但我不太倾向于仅仅因为 LINQ to Entities 已经可用而支持终止 LINQ to SQL。对象非常适合做对象所做的事情,这是毫无疑问的......在我(再次有偏见)看来,问题出现在人们将任何给定的工具或软件范例视为“灵丹妙药”并坚持一切一定是这样。众所周知,关系数据库非常擅长处理某些其他任务,报告就是一个很好的例子。所以在我看来,坚持一切都必须是实体是一种自取其辱的做法,因为这样你就强迫自己使用效率低下的工具来完成这项工作。因此,特别是在报告方面,抽象反转反模式。

所以我想我的答案的概要是这样的:如果您的问题是钉子,请使用锤子 - 如果您的问题是螺丝刀,请使用螺丝刀。

于 2009-01-19T21:07:11.557 回答
5

Dmitry 关于开发人员不喜欢 SQL 的说法可能有很多道理,但解决方案不仅仅是 ORM。解决方案是聘请开发 DBA 作为开发团队的一部分。在我的公司中,我的 .net 开发团队有一位出色的 Oracle DBA,他完全不从事任何生产 dba 工作。他在我们团队中的角色是数据建模、物理数据库设计、创建存储过程、数据分析等。他是我们的数据库端如此干净和执行的原因。我们所有的数据库访问都是通过存储过程。

什么是开发 DBA? http://www.simple-talk.com/sql/database-administration/what-use-is-a-development-dba/

于 2009-01-25T02:28:25.277 回答
4

我同时进行数据库和分布式应用程序编程(Web 和编译),并且觉得花时间开发基于存储过程的数据访问层是值得的。就个人而言,我更喜欢在开发过程的早期进行数据建模并确定所需的过程......似乎有助于发现设计/接口逻辑/结构问题。

我不是内联数据库编程的忠实粉丝(无论 sql 代码是手工生成的还是机器生成的)。我相信数据库是一个应用程序的基础,花时间手动编写存储过程是值得的。

也就是说,我对 OODBMS 概念很感兴趣,并希望有一天我能在生产环境中进行一些工作。

于 2009-01-19T20:55:02.863 回答
4

如果您希望数据库在扩展时执行,则必须根据数据库关系模型最佳实践对其进行设计和规范化。

如果您让对象模型和 ORM 决定您的数据模型,那么您最终会得到一个没有规范化和/或包含来自对象模型的工件的糟糕数据模型。

1 table = 1 class 是个坏主意。

首先,永远不会有代表多对多或多对一链接表的类。这些对应于对象模型中的子集合——链接本身不是对象。

如果你把你的数据库当作表来简单地把你的对象保存在行中(一种常见的方法)并让应用程序直接访问表,你就放弃了定义数据库可以用来保护的数据库服务接口层的所有好处它的周长。

ORM 有它们的位置,但是如果您使用它们来简单地保存对象模型中设计的对象,那么您的数据库将不是关系数据库,并且它不能用作 ETL、报告、重构等

于 2009-01-25T01:57:26.273 回答
3

我不喜欢任何当前的解决方案——但我更喜欢更多的选择而不是更少的选择;-)

我很久以前在一个项目中使用了一个 OODBMS,这是最接近正确的(不幸的是,该产品有一些令人发指的错误和糟糕的技术支持) - 对象持久性在很大程度上是不可见的,在幕后处理(通过预处理器代码生成器)和控制通过非常简单的 Update、Delete 和 Find 方法和简单的容器。

我很想再次看到这一点(也许某些对象实体模型已经做得很好),使用 OCL(对象约束语言)作为本机多对象查询语言

于 2009-01-19T19:31:12.920 回答
3

我认为这些事情背后的逻辑是,与系统其他部分的开销相比,在框架层构建和运行 SQL 语句的开销是微不足道的(例如,HTTP 请求往返时间要长几个数量级)。

优点 - 快速开发,适合语言而不是转义字符串的查询等,通常超过缺点。如果性能是一个问题,那么您可以稍后进行优化。

我不认为“不需要知道 SQL”是一个因素。任何体面的开发人员都需要在其开发的某个阶段了解 SQL。数据库抽象层的想法是消除为数据库查询生成样板代码的工作。

事实上,在我们的 Java 系统中,我创建了一个代码生成器实用程序,它采用带注释的类并生成一个完整的 CRUD API,并处理您随着时间的推移而获得的所有那些古怪的东西。创建模型并对其进行注释比费力地编写 DAO 容易得多。扩展这样的工具,您最终会得到 LINQ 或 Hibernate 或无数其他 ORM DB 解决方案。

于 2009-01-19T19:36:45.703 回答
3

这里还有一个关于 ORM 的问题。查看更多关于阻抗不匹配是否与所有这些一样重要的讨论。

于 2009-01-19T19:37:41.287 回答
3

我认为他们需要的真正解决方案更像是 SQL 文字。VB.Net 9.0 支持XML Literals,它允许您在代码中直接编写 XML,并确保它经过验证并符合 DTD。一个类似的好功能是 SQL 文字,它允许您在 .Net 代码中编写内联 SQL 代码,并通过 IDE 对其进行验证。需要某种插件架构来根据数据库验证信息,但这可以很容易地为流行的数据库引擎编写。这将为他们试图解决的问题提供我认为真正的解决方案,而无需求助于次优解决方案。

于 2009-01-19T19:37:44.343 回答
3

Codemonkey 提出了一个很好的观点:存储过程提供了一定程度的抽象,可以实现更复杂的 ORM 模型的一些承诺。乍一看这并不直观,但我可以直接从我自己的代码中想到一个示例。我有一个“签到”存储过程,它涉及近十几个表(此 ID 属于谁?他们有会员资格吗?有任何消息吗?他们是否为此签到获得积分?等等)。

在 C# 中对此进行建模 - 无论数据模型多么复杂 - 都不是一个好主意,因为它需要多次“通过网络”检查数据和更新各种表。虽然您确实可以在 Linq 或其他 ORMS 中处理存储过程,但我所需要的只是一个允许我使用标准 C# 参数调用存储过程的包装类。事实上,这对我来说是如此迫切,以至于我用 T-SQL 编写了一个代码生成器来创建这样的包装器。

于 2009-01-20T00:29:00.463 回答
2

我不得不同意,ORM 工具的爆发很大程度上源于编写 SQL、处理必须使用的任何 DB 驱动程序、在 DB 之间进行内部抽象(Oracle 与 SQL Server,与代码可重用性的任何东西)以及转换数据类型的烦恼.

理想的解决方案?绝对不是!但是,我认为这是更好地将应用程序与数据存储合并的过程中的一次迭代。毕竟,在大多数情况下,拥有一个没有使用任何语言编写的访问应用程序的数据库实际上是没有用的。(您真的会安装 oracle,并期望所有员工都直接在 SQLPlus 中工作吗?)

因此,我认为数据存储和应用程序只是以应用程序开发人员可以更轻松地与数据存储交互的方式一起移动。

特别是对于 .NET,我更愿意看到而不是 Linq 的是一种内置方式,用于将类定义映射到底层数据源到底层数据存储,并让所有管道正常工作。

换句话说,我可以说“Employee.Name = 'rally25rs';” 并且对象的属性会发生变化,并且在此之下它将持续到数据存储本身。完全放弃 SQL,而不是像现在的 Linq to SQL 那样采用 1/2 的方式。

当然,这样的解决方案会带来性能、事务处理等方面的问题。

也许编程语言和关系数据库的整个概念需要重新思考和重新调整?在它们的核心,它们是完全独立和脱节的实体。也许是时候放弃“关系 sql 感知数据库”并构建下一个东西了,执行一行代码将直接对数据库进行操作。

于 2009-01-19T20:11:07.507 回答
1

linq 没有问题,但是对于那些使用它并忽略“幕后”发生的事情的人

我仍然更喜欢用 SQL 来弄脏自己的手。至少我会确切地知道发生了什么。

于 2009-01-19T19:43:29.370 回答
1

Ted Neward 就他对这个主题的看法写了一篇很棒的文章 - ORM 是计算机科学的“越南”......

http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx

于 2009-01-19T22:04:06.607 回答
1

大多数人都忽略了一个要点:在大多数情况下,在 LINQ 中查询比在 SQL 中查询的效率要高得多。写了一篇关于为什么会这样的文章。

当我设置 LINQPad 挑战时,我并不是在开玩笑:我几乎所有的临时查询都是在 LINQ 中进行的,因为大多数查询在 LINQ 中比在 SQL 中编写得更快、更可靠。我还使用 LINQ to SQL 设计并处理了大型业务应用程序,并看到了生产力的重大提升。这不是“架构宇航员”的东西 - LINQ to SQL 是驱动这个站点的一种高效且实用的技术。

LINQ 的最大障碍是无法正确学习它。我已经看到很多 LINQ 查询是 SQL 查询的可怕音译来支持这一点。如果您仅使用 SQL 知识编写 LINQ 查询,则最终结果只能与 SQL 相同或更差。

于 2009-05-05T10:24:21.653 回答
1

我刚刚发现了这个问题。我想它现在已经差不多玩完了,但无论如何我都会投入两分钱......

我只想为不明显的事情编写代码。

CRUD 代码很明显。我不想写它。因此,ORM 是一个好主意。

这并不意味着 ORM 没有问题,但问题在于执行,而不是意图。随着 ORM 的成熟,问题将会减少,并且已经可用于简单场景的生产力提升最终也将扩展到复杂场景。

LINQ 也是一个好主意。其他人已经提到了许多优点,但我所要做的就是想想我第一次尝试在 LINQ 中进行枢轴操作时,我事先并不知道列数。或者我第一次意识到我不必DataView每次想要排序或过滤某些东西时都创建一个新的。LINQ 使我能够在 C# 中对数据做任何我想做的事情,而不必弄清楚如何在 SQL 和 C# 之间划分工作。

所以,是的,ORM、LINQ 和其他新兴技术是次优的解决方案,但它们不会错过重点,也不会永远是次优的。

于 2010-02-02T07:02:37.457 回答
0

我想写这个作为对@SquareCog 的回复在这里回复,但它告诉我我还剩下 -1836 个字符。如果我做错了,那么这里的菜鸟很抱歉。


18世纪休闲的绅士习惯于学习科学。那时,整个科学还不是一个相当聪明的人无法理解的大学科。我的意思是一个博学的人可以理解整个时代的科学思想。

随着时间的推移,已经发现了数百个新的科学领域,并且每一个都研究到了如今很少有人能够理解一个完整的科学领域的全部内容。

编程也是如此。

如今,编程语言领域已经足够大并且发展得足够快,以至于开发人员可以合理地期望了解他自己的全部专业语言。对于一个熟练的编码人员来说,也应该了解整个数据库领域,包括数据库设计、本机 SQL 的细微差别以及它如何在不同数据库上运行以及这些数据库的管理,可能要求有点高。

我认为这里的一些响应者正在掩饰开发大型高性能企业级数据库的一些复杂性,知道“少数 SQL 语句”肯定不会解决问题。这就是为什么大多数大型软件公司都有专门的数据库开发团队。正如 Stroustrup 所说,“分而治之”是有效处理开发和管理大型软件项目所固有的复杂性的唯一方法。

开发人员不喜欢使用 SQL 并不是因为他们懒惰或者因为这让他们感到“恶心”。他们不喜欢使用 SQL,因为他们很聪明。他们比任何人都清楚,只有精通 SQL 的人才会提供最高质量的数据库功能,而将他们置于“万事通”开发人员的位置是一种次优的开发策略。

于 2011-05-25T22:10:41.680 回答