NHibernate与LINQ to SQL的比较

117
作为一个没有在真实项目中使用过这两种技术的人,我想知道是否有人知道它们如何互补,以及它们的功能重叠程度有多大?
9个回答

113
LINQ to SQL 强制您使用 table-per-class 模式。使用此模式的好处是可以快速轻松地实现并且只需很少的工作即可基于现有数据库结构运行您的域。对于简单的应用程序,这是完全可以接受的(甚至更可取),但对于更复杂的应用程序,开发人员通常建议改用 domain driven design 模式(这就是 NHibernate 提供的功能)。
使用 table-per-class 模式的问题在于您的数据库结构直接影响您的域设计。例如,假设您有一个 Customers 表,其中包含以下列以保存客户的主要地址信息:
  • StreetAddress
  • City
  • State
  • Zip
现在,假设您还想添加列以保存客户的邮寄地址,因此将以下列添加到 Customers 表中:
  • MailingStreetAddress
  • MailingCity
  • MailingState
  • MailingZip
使用 LINQ to SQL,您的域中的 Customer 对象现在将具有每个这些八个列的属性。但是,如果您遵循领域驱动设计模式,则可能会创建一个 Address 类,并使您的 Customer 类持有两个 Address 属性,一个用于邮寄地址,一个用于当前地址。
那只是一个简单的例子,但它展示了表-类模式如何导致领域有点冗长。最终,这取决于你。对于只需要基本CRUD(创建、读取、更新、删除)功能的简单应用程序来说,LINQ to SQL非常理想,因为它很简单。但就我个人而言,我喜欢使用NHibernate,因为它可以促进更清晰的领域设计。
编辑:@lomaxx - 是的,我使用的例子过于简单,可以优化以适应LINQ to SQL。我想尽可能保持基本,以强调这一点。然而,重点仍然是,有几种情况下,让数据库结构确定领域结构都不是一个好主意,或者至少会导致次优的面向对象设计。

4
你可以使用 Linq To SQL 来编写你的代码实现,非常方便。 - Nicolas Dorier
1
我认为这不是ActiveRecord,即使映射类也封装了一些基础设施逻辑。如果你可以使用Customer.Save(),那么就是ActiveRecord模式。L2S使用DataContext类实现工作单元模式,类似于nHibernate中的Session,但NH有真正的POCO方法。 - Hrvoje Hudo
1
@kevin "LINQ to SQL使用活动记录模式"这是不正确的。这就像说ADO.NET使用活动记录,或者NHibernate使用活动记录一样。它们都是数据访问技术,并不强制执行任何特定的数据访问模式。我个人喜欢使用仓储模式来使用linq-to-sql。您是正确的,linq-to-sql不支持像NHibernate那样的复杂映射。 - liammclennan
1
你可以尝试对数据库进行规范化,然后使用工具(如SQLMetal)生成数据访问层(DAL)代码。 - Alex
3
当阻抗失配过大时,我认为您的应用程序过于复杂,无法使用LINQ to SQL。我的示例之所以有问题是因为使用LINQ to SQL将导致属性数量增加到8个而不是2个,并且限制了您实现一些函数或例程的能力,例如接受Address类或在Address类上实现例程,如果您使用NHibernate会更容易实现这些操作。 - Kevin Pang
显示剩余9条评论

26

目前有两个被忽略的问题:

  • LINQ to SQL 无法与 Oracle 或除 SqlServer 以外的任何数据库一起使用。 但是第三方提供了更好的对 Oracle 的支持,例如 devArt's dotConnectDbLinqMindscape's LightSpeedALinq。(我没有亲身体验过这些)

  • Linq to NHibernate 允许您在 Nhiberate 中使用 Linq,因此它可能消除了不使用它的原因。

此外,新的Nhibernate 流畅接口似乎使配置 Nhibernate 的映射变得更加轻松。 (消除了 Nhibernate 的痛点之一)


更新

Linq to Nhiberate 在现在的 Nhiberate v3 中更好,该版本现在处于alpha版。看起来 Nhiberate v3 可能会在今年年底发布。

自 .net 4 开始,Entity Frame Work 也开始成为一个真正的选择。


2
Linq to NHibernate仍处于非常早期的阶段。它不是一个完整的实现,可以说,根本没有准备好用于生产。 - liammclennan
新的LinqConnect 2.0版本引入了一些额外的便利功能,例如Table Per Type继承支持、PLINQ支持和批量更新功能。ORM Designer(Devart Entity Developer)现在具有模型优先支持和映射同步功能。更多详情请参见:http://www.devart.com/news/2010/dotconnects600.html - Devart

23

@Kevin: 我认为你所提出的例子存在的问题在于你使用了欠佳的数据库设计。我认为你应该创建一个客户表和一个地址表,并对表进行规范化。如果你这样做,你就可以绝对地使用Linq To SQL所建议的情景。Scott Guthrie有一系列关于使用Linq To SQL的很棒的博客文章,我强烈建议你去查看一下。

我认为你不能说Linq和NHibernate互补,因为这会暗示它们可以一起使用,尽管这是可能的,但更好的选择是选择其中一个并坚持使用它。

NHibernate允许您以高度灵活的方式将数据库表映射到域对象上。它还允许您使用HBL来查询数据库。

Linq to SQL也允许您将域对象映射到数据库,但它使用Linq查询语法来查询数据库。

主要的区别在于,Linq查询语法在编译时由编译器检查以确保您的查询是有效的。

需要注意的一些事情是,Linq仅适用于.net 3.x,并且仅支持VS2008。NHibernate可用于2.0和3.x以及VS2005。

NHibernate的一些注意事项是,它不会生成您的域对象,也不会生成映射文件。您需要手动完成这项工作。Linq可以自动为您执行此操作。


15
如果你正在编写针对一个遗留数据库结构的代码,而这个结构由于支持其他应用程序而无法更改。你想让你的领域模型继承糟糕的数据库设计,还是希望创建一个丰富的领域模型,使其能够与数据库结构独立变化? - Larry Foulkrod

7

Fluent NHibernate可以基于简单的约定来生成映射文件。无需编写XML,强类型化。

我最近参与了一个项目,我们需要出于性能原因从Linq To SQL切换到NHibernate。特别是L2S对象材料化的方式似乎比NHibernate慢,而且变更管理也相当缓慢。而且在不需要的特定场景下关闭变更管理可能很困难。

如果您要使用与DataContext断开连接的实体 - 例如,在WCF场景中 - 您可能会遇到许多连接它们以便更新更改的DataContext的问题。我在使用NHibernate时没有遇到过这种问题。

我会最怀念的L2S的东西主要是代码生成,它可以保持实体两端的关系最新。但我想NHibernate也有一些工具可以做到这一点...


2
以防其他人读了你的帖子并想要跳船 - 在你的DataContext上设置.ObjectTrackingEnabled = false将解决你的更改跟踪问题。只要你接受工作单元模式并不打算进行DDD,Linq-to-SQL真的可以发挥作用。 - mattmc3
"由于性能原因,我们需要从Linq To SQL切换到NHibernate" -- 使用了[Fluent,没有少] NHibernate几年后,我深有感触。我认为我们大部分时间都是通过编写本地SQL来处理真正的性能压力点,以此来作弊的。六年后听到您迁移的情况和是否值得的更新将是非常有趣的。 - ruffin

5

你能解释一下“LINQ”的意思吗?

LINQ并不是一种数据访问技术,它只是一种语言特性,支持将查询作为本地构造。它可以查询任何支持特定接口(例如IQueryable)的对象模型。

许多人将LINQ To SQL称为LINQ,但这完全不正确。微软刚刚发布了.NET 3.5 SP1的LINQ To Entities。此外,NHibernate具有LINQ接口,因此您可以使用LINQ和NHibernate来访问数据。


2
通过LINQ,我认为你指的是LINQ to SQL,因为LINQ本身没有与数据库相关的操作。它只是一种查询语言,具有大量的语法糖使其看起来类似于SQL。
在最基本的例子中,NHibernate和LINQ to SQL似乎都在解决同样的问题。但一旦你深入了解,你很快就会意识到NHibernate支持许多功能,可以创建真正丰富的领域模型。还有一个LINQ to NHibernate项目,允许您使用LINQ查询NHibernate,就像您使用LINQ to SQL一样。请注意保留HTML标签。

1
首先,让我们区分两个不同的事物:数据库建模关注数据,而对象建模关注实体和关系。
Linq-to-SQL 的优点是可以快速生成类来反映数据库模式,以便它们可以用作活动记录对象(请参阅活动记录设计模式定义)。
NHibernate 的优点在于允许您在对象建模和数据库建模之间保持灵活性。例如,可以根据性能等因素对数据库进行建模,以最好地反映您的数据。而使用诸如领域驱动设计之类的方法会更好地反映业务规则的元素。 (请参见Kevin Pang的评论)
对于具有较差建模和/或命名约定的遗留数据库,Linq-to-SQL将反映这些不需要的结构和名称到您的类中。但是,NHibernate可以通过数据映射器隐藏这种混乱。
在具有良好命名和低复杂度的数据库的新项目中,Linq-to-SQL可能是一个很好的选择。
然而,您可以使用Fluent NHibernate with auto-mappings来实现相同的目的,使用映射作为约定。在这种情况下,您不必担心任何数据映射器与XML或C#,并让NHibernate基于您可以自定义的约定从实体生成数据库模式。
另一方面,Linq-to-SQL的学习曲线比NHibernate小。

0

如你所写,“对于那些没有使用过它们的人” LINQ to SQL易于使用,因此任何人都可以轻松使用它 它还支持存储过程,这在大多数情况下都很有帮助。 假设您想从多个表中获取数据,然后编写一个存储过程并将该存储过程拖到设计器中,它将为您创建一切, 假设您的存储过程名称是“CUSTOMER_ORDER_LINEITEM”,它从这三个表中提取记录,然后只需编写

MyDataContext db = new MyDataContext();
List<CUSTOMER_ORDER_LINEITEMResult> records = db.CUSTOMER_ORDER_LINEITEM(pram1, param2 ...).ToList<CUSTOMER_ORDER_LINEITEMResult>();

你也可以在foreach循环中使用你的records对象,这是NHibernate不支持的。


0

或者你可以使用Castle ActiveRecords项目。我最近在一个遗留项目中使用了它来快速启动一些新的代码。它使用NHibernate并且基于活动记录模式(尽管名字有些让人惊讶)。虽然我没有尝试过,但我认为一旦你使用了它,如果你感觉需要直接使用NHibernate支持,那么你就可以这样做,而这不会太困难,可以应用到你的整个项目中或其中的部分。


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