【问题标题】:NHibernate vs LINQ to SQLNHibernate 与 LINQ to SQL
【发布时间】:2010-09-06 19:39:20
【问题描述】:

作为一个没有在实际项目中使用过这两种技术的人,我想知道是否有人知道这两种技术如何相互补充以及它们的功能有多少重叠?

【问题讨论】:

    标签: linq nhibernate linq-to-sql orm


    【解决方案1】:

    你能解释一下“LINQ”是什么意思吗?

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

    许多人将 LINQ To SQL 称为 LINQ,但这根本不正确。 Microsoft 刚刚发布了带有 .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 的方式大致相同。

      【讨论】:

        【解决方案3】:

        LINQ to SQL 强制您使用每类表模式。使用这种模式的好处是它快速且易于实现,并且只需很少的努力就可以让您的域基于现有的数据库结构运行。对于简单的应用程序,这是完全可以接受的(通常甚至更可取),但对于更复杂的应用程序,开发人员通常会建议改用 domain driven design 模式(这是 NHibernate 所促进的)。

        table-per-class 模式的问题在于您的数据库结构对您的域设计有直接影响。例如,假设您有一个 Customers 表,其中包含以下列来保存客户的主要地址信息:

        • 街道地址
        • 城市
        • 状态
        • 邮编

        现在,假设您还想为客户的邮寄地址添加列,因此您在客户表中添加以下列:

        • MailingStreetAddress
        • 邮寄城市
        • 邮件状态
        • 邮寄邮编

        使用 LINQ to SQL,您域中的 Customer 对象现在将具有这八列中的每一列的属性。但是,如果您遵循域驱动的设计模式,您可能会创建一个 Address 类并让您的 Customer 类拥有两个 Address 属性,一个用于邮寄地址,一个用于当前地址。

        这是一个简单的例子,但它演示了每类表模式如何导致一个有点臭的域。最后,这取决于你。同样,对于只需要基本 CRUD(创建、读取、更新、删除)功能的简单应用程序,LINQ to SQL 是理想的,因为它很简单。但就我个人而言,我喜欢使用 NHibernate,因为它可以使域更干净。

        编辑:@lomaxx - 是的,我使用的示例很简单,并且可以进行优化以与 LINQ to SQL 很好地配合使用。我想尽可能地保持基本,以便把重点放在家里。重点仍然存在,在某些情况下,让您的数据库结构决定您的域结构将是一个坏主意,或者至少会导致 OO 设计欠佳。

        【讨论】:

        • 您可以使用 Linq To SQL 对您的存储库的实现进行编码,非常方便。
        • 我认为它不是 ActiveRecord,甚至映射类都封装了一些基础架构逻辑。 ActiveRecord 模式将是如果您可以拥有 Customer.Save()。 L2S 使用 DataContext 类实现 Unit of Work 模式,类似于 nHibernate 中的 Session,但 NH 有真正的 POCO 方法。
        • @kevin "LINQ to SQL 使用活动记录模式" 这是不正确的。这就像说 ADO.NET 使用活动记录,或者 NHibernate 使用活动记录。它们都是数据访问技术,不强制执行任何特定的数据访问模式。我个人喜欢将 linq-to-sql 与存储库模式一起使用。你说得对,linq-to-sql 不支持像 NHibernate 那样的复杂映射。
        • 如何规范化您的数据库,并让您的 DAL 由工具(例如 SQLMetal)生成?
        • @CoffeeAddict 当阻抗失配太大而无法承受时,就是当您的应用程序过于复杂而无法在 imo 上使用 LINQ to SQL 时。我的例子很臭的原因是因为使用 LINQ to SQL 会产生 8 个属性而不是 2 个,并且会限制您执行诸如实现接收地址类的函数或在地址类上实现您可以执行的例程之类的事情的能力如果您使用过 NHibernate,请执行此操作。
        【解决方案4】:

        或者您可以使用 Castle ActiveRecords 项目。我一直在使用它来为遗留项目增加一些新代码。它使用 NHibernate 并适用于活动记录模式(我知道它的名字令人惊讶)。我没有尝试过,但我假设一旦你使用了它,如果你觉得有必要直接放弃 NHibernate 支持,那么对于你的部分或全部项目来说这样做不会太多。

        【讨论】:

          【解决方案5】:

          @Kevin:我认为您所展示的示例的问题在于您使用了糟糕的数据库设计。我原以为您会创建一个客户表和一个地址表并规范化这些表。如果您这样做,您绝对可以将 Linq To SQL 用于您建议的场景。 Scott Guthrie 有一个great series of posts on using 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可以
          自动为您执行此操作。

          【讨论】:

          • 如果您针对旧数据库结构编写代码,您无法更改,因为它支持其他应用程序。您是希望您的域模型继承糟糕的数据库设计,还是希望创建一个可以独立于数据库结构而变化的丰富域模型?
          【解决方案6】:

          目前遗漏的两点:

          • LINQ to SQL 不适用于 Oracle 或除 SqlServer 之外的任何数据库。 但是,第三方确实为 Oracle 提供了更好的支持,例如devArt's dotConnectDbLinqMindscape's LightSpeedALinq。 (我对这些没有任何亲身经历)

          • Linq to NHibernate 让你使用 带有 Nhiberate 的 Linq,所以它可能 删除不使用的理由。

          此外,新的fluent interface to Nhibernate 似乎让配置 Nhibernate 的映射变得不那么痛苦。 (去除Nhibernate的痛点之一)


          更新

          Linq to Nhiberate 在 Nhiberate v3 中更好,现在在 alpha 中。看起来 Nhiberate v3 可能会在今年年底发布。

          .net 4 中的Entity Frame Work 也开始看起来像一个真正的选择。

          【讨论】:

          • Linq to NHibernate 仍处于非常早期的阶段。它不是一个完整的实现,并且可以说根本没有准备好用于生产。
          • 新的 LinqConnect 2.0 版本为方便起见引入了一些附加功能,例如 Table Per Type 继承支持、PLINQ 支持和批量更新功能。 ORM Designer(Devart Entity Developer)现在具有模型优先支持和映射同步功能。更多详情:devart.com/news/2010/dotconnects600.html
          【解决方案7】:

          Fluent NHibernate 可以根据简单的约定生成映射文件。没有 XML 编写和强类型。

          我最近参与了一个项目,出于性能原因,我们需要从 Linq To SQL 更改为 NHibernate。尤其是 L2S 实现对象的方式似乎比 NHibernate 的同上慢,而且变更管理也很慢。对于不需要的特定场景,很难关闭变更管理。

          如果您要使用与 DataContext 断开连接的实体(例如在 WCF 场景中),您可能很难再次将它们连接到 DataContext 以更新更改。我对 NHibernate 没有任何问题。

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

          【讨论】:

          • 以防其他人阅读您的帖子并考虑跳槽 - 您的 DataContext 上的 .ObjectTrackingEnabled = false 将解决您的更改跟踪问题。只要您接受工作单元模式并且不打算使用 DDD,Linq-to-SQL 就可以真正做到。
          • "出于性能原因,我们需要从 Linq To SQL 更改为 NHibernate" -- 使用 [Fluent, not less] NHibernate 几年了,我对你有好感.我认为我们主要是作弊并最终为真正的性能压力点编写原生 SQL。听到有关您的迁移进展情况以及是否值得的更新(六年后......)会很有趣。
          【解决方案8】:

          正如你所写的“对于一个没有使用过它们的人” 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 循环中使用你的记录对象,NHibernate 不支持这个

          【讨论】:

            【解决方案9】:

            首先让我们分开两个不同的东西: 数据库建模关注数据,而对象建模关注实体和关系。

            Linq-to-SQL 的优势是可以从数据库模式中快速生成类,以便它们可以用作活动记录对象(请参阅活动记录设计模式定义)。

            NHibernate 的优势是允许您的对象建模和数据库建模之间的灵活性。例如,考虑到性能,可以对数据库进行建模以最好地反映您的数据。虽然您的对象建模将使用诸如领域驱动设计之类的方法最好地反映业务规则的元素。 (见 Kevin Pang 评论)

            对于建模和/或命名约定不佳的遗留数据库,Linq-to-SQL 会将这种不需要的结构和名称反映到您的类中。然而 NHibernate 可以用数据映射器隐藏这种混乱。

            在数据库具有良好命名和低复杂性的新建项目中,Linq-to-SQL 可能是不错的选择。

            但是,您可以将 Fluent NHibernate 与自动映射 用于同样的目的,并将映射作为约定。在这种情况下,您不必担心任何带有 XML 或 C# 的数据映射器,并让 NHibernate 根据您可以自定义的约定从您的实体生成数据库模式。

            另一方面,Linq-to-SQL 的学习曲线比 NHibernate 小。

            【讨论】:

              猜你喜欢
              • 2019-10-08
              • 1970-01-01
              • 1970-01-01
              • 2010-09-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多