Linq to SQL是否失去了重点?ORM映射器(SubSonic等)是否是次优解决方案?

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查询字符串添加到Command类中,执行命令,然后使用(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),并且对于日期处理(例如 DateDiff)、"Having" 甚至 "Group By" 等 SQL 构造的支持非常笨拙(充其量)。
那还有什么替代方案呢?个人认为不需要像 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而消除阻抗不匹配的基本方法非常吸引我。
问题是:我错了吗?Microsoft是否应重写SQL基础架构,以便您不再需要学习SQL /关系数据管理?他们能以这种方式重写SQL基础设施吗?或者您认为在SQL之上加一个非常薄的层以消除设置参数和访问数据字段的痛苦已经足够了吗?
更新:我想将两个链接提升到顶部,因为我认为它们捕捉了我所追求的重要方面。首先,CodeMonkey指出一篇名为"计算机科学的越南战争"的文章。它需要一段时间才能开始,但非常有趣。其次,AnSGri指向Joel Spolsky的一篇更为突出的文章:泄漏抽象法则。它不完全相关,但很接近并且是一篇好文章。
更新2:我已经向ocdecio提供了“答案”,尽管这里有许多很好的答案,选择“正确”的答案纯粹是主观的。在这种情况下,他的答案符合我认为是当前技术状况下最佳实践的要求。然而,我完全希望这个领域会发展,所以事情可能会有所改变。我要感谢所有做出贡献的人,我已经给出了我认为给出了深思熟虑的答案的人点赞。

非常好的问题。我记得在TechDays上问过微软的一个人,关于微软未来的方向,是Linq、Entities等等。他似乎也不知道... - Benjol
2
从你选择的答案和评论来看,很明显这不是一个问题,而是一篇观点文章。把它放在你的博客上吧。 - mcintyre321
2
麦金太尔 - 你在说什么?这是一个非常受欢迎的问题,引发了很多辩论和讨论(正如Benjol所说:“非常好的问题”)。从我所知道的情况来看,即使他们不同意我的“答案”,也有相当多的人从中学到了一些东西。我对SO的看法是,它是一个探索整个软件开发领域的地方,我已经做了很多工作来帮助它朝着这个方向发展。唯一真正的缺点是,有很多人认为在不同意别人的观点时使用粗鲁的言语是合适的。 - Mark Brittingham
不,问题在于这已经成为了你个人观点的平台,而不是对ORM本质的深入探讨。你没有解释ORM如何促进DDD和TDD,也没有涉及到伴随ORM的二级缓存等次要特性,你没有提到ORM支持IQueryable接口和可组合谓词的好处,你没有指出ORM-less解决方案往往充满危险的“魔术字符串”,也没有提到像l2s或nhibernate这样的“复杂”产品比你自己编写的DAL解决方案具有更好的稳定性/功能比率。 - John Farrell
jfar - 或许你可以把这些批评放在回答里,让人们评论和投票,而不是放在这里(其中很多都很有趣,值得讨论)。然而,我有几个想法。你真的想让这篇文章变得更吗?我并不想解决所有问题!此外,ORM与TDD相当正交(你当然可以在没有它们的情况下进行TDD),我不希望二级缓存被重新实现(ADO.NET中已经存在缓存),而且很容易,IQueryable接口不是ORM的特性——它是.NET的基本特性(我广泛使用它)。-续- - Mark Brittingham
显示剩余3条评论
24个回答

45

让我先说一下,我是一个执着于数据库的人。

笼统地说:开发人员不懂 SQL。他们不太去学 SQL。他们可以编写它,设计表格,但这会让他们感到不舒服。当需要查询超过简单的连接时,他们往往会做一些愚蠢的事情。这并不是因为开发人员愚蠢 - 只是因为他们不能被打扰。他们喜欢生活在一个只涉及一个概念空间的世界中;从对象到表格再返回来需要进行上下文切换,而他们不愿支付这个代价。

这并不意味着他们不好或者错了;而是存在改进的机会。如果你的客户(在这种情况下,使用你的框架的开发人员)不喜欢 SQL 和表格 - 给他们一个抽象层,让他们不必处理底层混乱。

这是使垃圾收集/自动内存管理成为热门的相同逻辑。是的,开发人员可以处理它;是的,他们可以编写更优化的代码,但不必处理它使他们更加快乐和有效率。


7
我完全不同意。SQL很容易。你只需要掌握少量关键字就可以了。写得好、性能高的SQL可以显著提升应用程序的速度。而糟糕的SQL会使关系型数据库管理系统和网站陷于瘫痪。如果您不想编写SQL,只需说出来即可。 - DOK
1
你在对DOK讲已经被信徒接受的道理。我只是想说,教堂外也有音乐 :-) - SquareCog
13
这真的很遗憾:数据处理是良好编程的核心。不掌握 SQL 就像决定成为吉他手却不喜欢弦和弹奏和弦一样。 - Mark Brittingham
2
这就是我猜测的。我是一名开发人员,我喜欢SQL。但我认为这并不常见。 - Jeff Davis
我喜欢垃圾回收和ORM之间的类比。+1 - gn22
显示剩余4条评论

36

我认为ORM的普及是由开发人员在应用程序之间开发数据层并反复编写相同的CRUD代码所引发的。 ORM只是另一种工具/技术,它让开发人员花费更少的时间重复编写相同的SQL语句,而将注意力集中于应用程序的逻辑上(希望如此)。


1
Jim,我认为你是完全正确的。问题在于当前的方法是否过度解决了这个问题。我没有说过这个,但我已经开始开发一个代码生成器来创建围绕SQL查询的类供我自己使用。Linq/SubSonic对我来说不起作用。 - Mark Brittingham
绝对正确。当我到达数据层并意识到“需要为所有对象编写200个SQL查询”时,我完全停止了侧面项目的工作。ORM工具可以极大地加速这一过程。不幸的是,大多数ORM工具都很糟糕 :( - CodingWithSpike
我认为这是个人选择。你总是可以像在ORM流行之前那样编写自己的数据访问层并拥有完全控制权,但ORM通常提供了一个可接受的DAL框架(即使存在缺陷)以节省大量时间和工作量。 - Jim Anderson
1
“节省大量时间和工作”是一个有争议的说法。这不是我的主观经验,但我会相信这是你的经验。我认为DAL并不特别困难或繁琐,除非你在浪费时间制作CRUD模板(它们命名得很好,不是吗?) - dkretz
@le dorifier:是的,我猜你的经验可能会有所不同。但考虑到创建像Hibernate和Entity Framework这样的产品所花费的时间,我希望它们能够增加价值并减少所需的数据“管道”代码。 - Jim Anderson
显示剩余2条评论

18

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

我对我所拥有的感到满意,没有找到任何值得放弃它的东西。


4
我一直在做同样的事情。对于比单行选择/更新/删除操作更复杂的任何操作,您可能需要编写自定义 SQL,因此我认为不需要像 Linq 这样的东西。 - Kibbee
1
应该不难看出,LINQ是另一个抽象层;但这已经够多的了。它没有解决任何已知的抽象问题,如果真有的话,就会有一个问题被解决掉了。但在这里却找不到这样的候选者。 - dkretz
2
我并没有试图解决抽象问题 - 我只是想让将SQL查询转换为对象以及将对象转换回数据库变得更加容易,就这么简单。这缩短了我的开发时间,提高了我的整体代码质量,这正是我所追求的。 - Otávio Décio
2
@Jeff - 你可以在 http://databroker.codeplex.com/ 找到它,我把它放在那里以便集中管理。请随意查看并通过联系页面告诉我(如果您有问题/建议/批评),我非常欢迎。 - Otávio Décio
@Otávio Décio,感谢您公开提供代码,真的很有趣能看到ORM模式的实际应用。@Tom Bushell,顺便说一下,这并不使用“Active Record”模式,而是使用“数据映射器”和“工作单元”模式的组合,正如《企业应用架构模式》中所描述的那样。与Active Record有一个相似之处:对象属性名称必须与数据库字段名称匹配,但这并不意味着它是Active Record。 - Ash
显示剩余9条评论

12

在我看来,OR/M 不仅仅是抽象 SQL 或隐藏 SQL,或者支持多 DBMS。

它能让你更加专注于问题域,因为你不必花费太多时间编写乏味的 CRUD SQL 查询。另一方面,如果你使用一个好的 OR/M,这个 OR/M 应该能够在必要时让你编写 SQL 查询。

如果你正确地使用 OR/M,它可以成为一个强大的工具;它可以处理延迟加载、多态查询 / 关联等等。
不要误解我的意思;纯 SQL 并没有错,但是,如果你自己要负责将(经过深思熟虑和归一化的)关系模型转换为表达力强的 OO/domain 模型,那么我认为你会浪费太多时间做管道工作。

使用 OR/M 也并不意味着你 - 作为开发者 - 不需要了解 SQL。相反,在我看来,了解 SQL 和知道如何编写高效的 SQL 查询,将使你能够正确地使用 OR/M。

我也必须承认,我写这篇文章是想到了 NHibernate。这是我目前正在使用的 OR/M,我还没有使用过 Linq to SQL 或 Linq to entities。


3
我和你有同样的经历。编写粗糙的SQL语句很容易,关键是不用反复地编写和修改管理这两个世界映射的管道/粘合剂。在团队中特别是有许多开发人员时,始终保持一致性是很困难的。ORM映射器可以让每个人都忘记这些细节并统一进行操作。 - Daniel Auger

10
Linq的设计以及Linq to Entities框架确实有作为ORM工具的用途,但其大想法是将其用作查询任何数据源的通用API,而不仅仅是关系型数据库。我记得阅读过Linq的设计是考虑了SQL,但旨在成为任何数据存储的查询语言。您可以编写针对SQL的Linq查询,但理论上也可以编写针对LDAP、文件系统、Exchange、Web服务等的Linq查询。这些程序不能使用SQL。
此外,您还需要为几乎每个数据存储学习不同的API。Linq为每个人提供了一个共同的目标,创建数据访问API。
这种愿景是否可行尚待观察,但这就是想法。随着我们希望系统之间的互操作性越来越强,我们可能会发现一些非常好的L2E用途。
如果我能再次找到它们,我会添加一些参考资料。

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


9
我完全同意。很多都是由于过程式编程技能和SQL编程技能非常不同造成的,而这个事实并没有被广泛认可。所以,在这个认识到来之前,程序员会寻找方法使他们的技能从一个领域转移到另一个领域。
这是行不通的。
你必须学会如何相位移:学会根据你所处理的领域不同而以不同的思维方式来思考你的代码。
还有其他人注意到当一个查询从SQL映射到LINQ时,它变得多么复杂和冗长吗?就像在线例子中一样?

1
除了“必须”这个词,我同意你所说的一切。面对现实吧——在Java的世界里,我们是C语言黑客。我们的代码可能运行得更高效,但是我们越快接受现状,我们的血压就会越低 :-). - SquareCog
4
相反的是,在LINQ中,大多数查询变得更加简单。问题在于许多人未能正确学习LINQ,因此他们将SQL查询“音译”成LINQ - 当然,这样你只会失去而不会获得。 - Joe Albahari
我很高兴对你来说这变得“更简单”了。对我来说,这是将简单的东西翻译成不同的东西,无可争议地增加了复杂性。而且,并不总是完全匹配。 - dkretz
是的,声明式编程==很棒。 :) - Jeff Davis

9
你应该停止担心,学会喜欢ORM。这样的抽象将帮助我们专注于技能并在领域中取得进展。
仍然有足够的空间利用您已经掌握的功能技能并将其应用于应用程序层。事实上,这是LINQ到SQL优于其他ORM的优点之一。
我只能同意许多其他评论。您节省的时间可以专注于完善您的领域模型并创建更好的应用程序。而且,一旦您确定了瓶颈,可以使用它来创建优化后的SQL。
可能不是立即显而易见的是,ORM带有许多非常好的功能。标识映射有助于避免反复加载项目,延迟加载可帮助您使用更少的管道表达域,工作单元可帮助您跟踪更改并优化数据库写入。

1
然后我们需要发明和实现一个数据存储,与对象范式相匹配,而不是强制适应SQL。你只是将阻抗不匹配移动到接口的另一侧。 - dkretz
3
“停止担心”是在这个行业中生活的可怕方式。“对一切提出质疑”要好得多。 - CodingWithSpike
此外,抽象化并不总是好事。它导致使用工具之间的共同点,而没有专业化。例如:将其抽象化为“DB”,您必须删除Oracle持续通知,甚至存储过程,因为并非所有的DB都有这些功能。 - CodingWithSpike
@Frederik,是的,他们必须一起工作 - 我们已经这样做了多年。然而,这个问题是关于ORM映射器是否简化了任何事情。我们中的许多人已经很高兴使用我们已经知道的语言创建DAL来与我们已经知道如何编写的SQL进行通信,以处理不匹配。 - dkretz
@Christian 对于“这些抽象将帮助我们集中精力...”,我赞成。我同意在使用C#处理旧的、原始的SQL接口工具是浪费时间的。像其他人一样,我编写了一个DAL来抽象化所有这些内容。我对Linq的批评是,作为一种抽象,它过于努力地追求理论上的纯净(参见ACM通信最近的文章),而牺牲了我们已经知道或应该知道的工具(SQL)的发挥。 - Mark Brittingham
显示剩余3条评论

7

正如Dmitriy所指出的,开发人员不了解SQL。更准确地说,大多数人 知道 SQL,但不 理解它,也肯定不喜欢它,因此他们倾向于寻找魔法弹药,创建诸如Linq之类的东西,以产生他们不使用任何与他们心爱的类不同的东西的幻觉(嗯,抽象)。

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

一些ORM解决方案是绝对好的(例如JPA / Hibernate),并不是因为使用它们你不必担心SQL。实际上,要有效地使用JPA,你需要对DB有非常深入的理解,尤其是查询能力。好处是它们可以让机器做无聊的工作,甚至可以自动生成整个数据库。

Linq to SQL,我认为并没有解决实际问题。它只是一种其他呈现方式,仅此而已。尽管它可能很好用,但它使本来就复杂的语言更加复杂了。另一方面,Linq to Objects 是非常有趣的概念,因为它可以对集合进行类似于 SQL 的查询。

6

历史背景。

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

如果微软有一个好的故事,他们正在恢复这些其他语言中的一种,或者发明了一个值得的补充,那么我认为我们应该好好听听。但到目前为止,我所看到的只是另一个“一环控制它们所有”。

SQL背后有大量的思考和严谨性,以及长期经过时间检验的耐久性。微软有一定的历史,认为他们的确拥有顶级的开发组织,可以超越我们所有人,包括我们集体的机构记忆。似乎这种想法并不常见。只要我们与关系数据存储绑定,我们应该三思而后行,不要远离裸金属,以平等或更好的性能为诱饵的超集抽象范例。


我实际上使用了QBE,因为它在上世纪90年代早期的“Paradox”数据管理工具中得到了实现,所以我还记得!你对“一枚戒指统治他们”的比喻是无价之宝! - Mark Brittingham
我认为这个类比是无用的。LINQ 是为解决阻抗不匹配而设计的,而不是另一个关系型查询语言。 - reinierpost
QUEL是Berkeley Ingres的原始查询语言,与SQL并没有太大的区别,但很快就被SQL取代了。QBE是一个基于SQL的图形/文本GUI,对于简单的查询非常方便,但对于复杂的查询则不太适用。我认为这两种语言都不能与SQL相提并论。SQL是一种非常强大、表达能力极强的语言。 - Jim Ferrans

5
作为一个ORM项目的作者,我必须承认我的回答可能会有些偏见。在阅读问题之前,我已经对答案有了一些自己的想法,所以我已经有了一定的锚定点。
我要说的是,我开发ORM的原因不是因为SQL和命令式编程之间存在“阻抗不匹配”,而仅仅是为了成为数据库平台无关的。前者需要编写更多的代码来管理持久性,这是一个小障碍,如果你只与一个数据库供应商合作,很容易解决。成为数据库平台无关则是一个更具挑战性的问题,在我看来,它对你的业务的盈利能力有着更大的影响,假设像我一样,你计划向其他人出售软件(而不仅仅是在内部使用)。
当我几年前开始开发我的ORM工具时,在我偏爱的语言中,这个概念是不切实际的,大多数人不理解我为什么要开发它,社区中一些备受尊重的声音甚至在贸易杂志上撰写文章,声称我已经完成的内容不仅不可能,而且也不可取。给出了一些相同的原因 - 它太复杂、限制性太强、增加了开销。今天,同样的社区至少有三种流行的数据库抽象工具(虽然对于ORM术语的定义存在争议)。我提到这个原因是因为当我开始开发这些工具时,最初的反对意见比现在更具有说服力。硬件和软件的基础技术在这些年间发生了变化,使得这些工具在长期内变得更加实用。我的倾向是尝试着从长远的角度看待软件,并致力于解决那些可能还不太实用但很快就会变得实用的问题。因此,考虑到这一点,我认为LINQ to Entities是某些问题的一个好解决方案。
我更倾向于拥有更多的选项而不是更少。因此,虽然我可能支持开发LINQ to Entities的想法,但我不太可能仅仅因为LINQ to Entities已经可用就支持杀掉LINQ to SQL。对象非常适合做对象所做的事情,这是毫无疑问的...在我的(再次带有偏见的)意见中,问题在于人们将任何给定的工具或软件范例视为“万能药”,并希望坚持认为一切都必须这样。众所周知,关系型数据库非常擅长处理某些其他任务,报告就是一个很好的例子。因此,在我看来,坚持认为一切都必须是实体,就像你强迫自己使用一种效率低下的工具来完成工作一样,这是在自毁前程。所以特别是在报告方面,摆脱LINQ to SQL并仅使用LINQ to Entities至少在表面上听起来像是抽象反转反模式。
因此,我对我的答案的概述是:如果你的问题是钉子,请使用锤子;如果你的问题是螺丝,请使用螺丝刀。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接