将 Linq 中的 NHibernate 应用程序重写为 SQL

Posted

技术标签:

【中文标题】将 Linq 中的 NHibernate 应用程序重写为 SQL【英文标题】:Rewriting NHibernate app in Linq to SQL 【发布时间】:2010-10-01 15:07:57 【问题描述】:

我有一个使用 NHibernate 编写的过时的旧应用程序。现在我想重写它,包括新功能和模型的重大变化。

使用 Linq to SQL 代替 NHibernate 的主要缺点是什么?

使用 LINQ to SQL 可能会出现哪些问题,将 DataContext 设置为单例会导致性能下降吗?

【问题讨论】:

有没有理由专门在LinqToSql中重写呢?是否可以在 NHibernate(最新版本)或实体框架中重写它?所有这些不同的框架都提供不同的功能,所以这完全取决于你的模型和关系的简单或复杂程度...... 【参考方案1】:

来自"The false myth of encapsulating data access in the DAL":

“我想使用 NHibernate 设计一个系统/应用程序。但是我 也想如此灵活,以至于将来,如果我拔掉NHibernate 然后使用 ADO.NET Entity 框架或其他框架 应用程序不应崩溃。”

总之,我完全反对 甚至尝试做类似的事情。

它基于有缺陷的假设

这背后的很多驱动力是 基于内置的历史驱动器 数据访问层的时间 使用其直接访问数据库 自己的方言,导致需要 在 为了支持多个数据库。

这个驱动器的问题是它 不再是一个因素,所有现代 OR/Ms 可以处理多个数据库 有效地。此外,现代 OR/M 是 不再只是执行某些操作的方法 SQL 并返回一个结果,即 旧式 DAL 是如何编写的。一个 OR/M 承担更多责任 责任,从诸如 更改跟踪到缓存管理, 从确保乐观并发 与管理最佳沟通 数据库。

这些功能非常重要。不是 仅此而已,但它们是不同的 在每个 OR/M 之间。

它不起作用,你会发现为时已晚

主要问题是无论如何 你努力,会有的 微妙的和不那么微妙的差异 在不同的 OR/Ms 之间,这些变化 会极大地影响您的构建方式 你的申请。

那么你如何在 OR/Ms 之间移动?

有些人想要从一种数据访问技术转向另一种是有原因的。我参与了几项此类工作,我们在每种情况下使用的方法是移植,而不是尝试删除新的 IDataAccess 实现。

【讨论】:

【参考方案2】:

一个巨大的问题,但在从 L2S 到 NHibernate 2.x 的大规模重构过程中,我意识到的一件事是 NHibernate 允许在与派生不同的物理表中表示基类。但是对于 L2S,我不得不使用 1 个单表来表示基类以及将扩展它的每个类。

这允许我创建更小的表,因为我有一个基类,它被大约 25 个不同的子类变体继承。如果您想继续使用此功能,它可以帮助简化您的架构。

【讨论】:

一个基类被 25 个子类继承?听起来很可怕(很复杂) 哈哈,现在回想起来,我确信接口可以解决问题,而不是将每个人都耦合到基类。然后通过组合我可以重用有问题的方法。【参考方案3】:

使用 Linq to SQL 代替 NHibernate 的主要缺点是什么?

LINQ to SQL 的优点

更高级和更易于使用 (恕我直言) 查询语法,特别是它使用 LINQ 执行查询,从而为您提供强类型/编译时安全查询。 NHibernate 为您提供 HQL,虽然功能非常强大,但都是基于字符串的。 NHibernate 也有 Criteria 查询,它的类型更强一些(仍然是一些字符串),但它的语法/API 很难理解。

NHibernate v2 确实有一个可以下载的 LINQ 提供程序,但它有点缺乏(事实上很多缺乏),它不支持大量用例。 NHibernate 3.0 自带内置的 LINQ 提供程序,功能更强大,几乎可以与 LINQ 2 SQL 或 EF 媲美。


LINQ to SQL 的缺点

几乎所有其他内容!说真的,我从哪里开始:

简单的表到实体的映射,不像NHibernate有更强大的映射能力包括:单向关联,组件映射,可以映射public IList<string> Tags get; set; 等值类型的集合,继承映射(非常强大),枚举映射,还有更多...

您的实体与 LINQ to SQL 紧密耦合,这会影响单元测试。 NHibernate 支持 POCO 映射,这对于实现松散耦合、可维护、可单元测试的代码库很重要。

支持更多数据库(SQL Server、mysql、PostgreSQL、Oracle、SQLite 等)。 LINQ 2 SQL 仅支持 MS SQL Server。

能够使用 NHibernate 在您的应用程序中实现 DDD(域驱动设计)原则。 LINQ 2 SQL 更多地是您的域模型的以数据库为中心的视图,而 NHibernate 则更多地以您的域的业务/行为为中心的视图。

说真的,采用 NHibernate 应用程序并将其“降级”到 LINQ 2 SQL 似乎是倒退了一步。如果你想使用更微软的东西,至少考虑使用 Entity Framework 4.0。 LINQ 2 SQL 在只有几个表的简单应用程序中占有一席之地,但任何更复杂的应用程序都需要更强大的 ORM。

【讨论】:

更高级的查询语法?怎么会? LINQ 2 SQL:没有延迟加载。瞬间失败。 不要忘记 linq 超过 NH 的标准 :) @Diego Mijelshon:也许更高级的词用错了。也许更容易使用。我只是发现编写 LINQ 比编写 HQL 或 ICriteria 查询要容易 10 倍,而且 LINQ 让我几乎可以做任何事情(投影、分组、排序、连接、子查询等)。难怪他们在 NHibernate 3.0 中添加了一个专用的 LINQ 实现 更正确,但我仍然不同意。 LINQ to [任何数据库技术] 是一种高度泄漏的抽象,只有在您不知道(或不想学习)HQL 时才会更容易使用。【参考方案4】:

当我构建一个应用程序时,它有一个简单的域和一个基本架构,我喜欢 Linq2Sql。 Linq 写的很快,我可以很快把事情做完。我意识到那里有一个 Linq2NHibernate,但我不确定它的成熟度如何。一些缺点,IMO 到 Linq2Sql 必须在架构更改时重新生成类和 DataContext,并且必须从 Linq2Sql 生成的类映射到我的域对象。对于简单的小项目,我真的不介意这样做。虽然使用 FluentNHibernate 和 Linq2NHibernate,但我使用 NHibernate 可能与使用 Linq2Sql 一样高效,但我还没有尝试过。

我在一个项目中使用 Linq2Sql 来处理一个过度规范化的数据库,该数据库具有一些复杂的域,这是一场噩梦。它奏效了,我们能够从中获得一些不错的性能,但可维护性几乎不存在。但是对于这种模式,我不确定 NHibernate 或直接 SQL 是否会改变它。在我看来,这是一个毫无疑问的案例,文档数据库本来就是要走的路。

如果该项目已经使用 NHibernate 完成,并且您有这种经验,我会坚持下去。您可以直接映射到您的域对象这一事实很棒。当架构在开发早期发生变化时,Linq2Sql 代码生成可能会很痛苦。最重要的是,Linq2Sql 实际上已经死了。 MS 正在将其所有 ORM 鸡蛋放入实体框架篮子中。

【讨论】:

【参考方案5】:

与其做一个完整的移植,也许你只需要对你的 NHibernate 层进行 LINQ 化...

http://www.hookedonlinq.com/LINQToNHibernate.ashx

一些额外的阅读材料:

http://www.caffeinatedcoder.com/linq-to-nhibernate/

引用:

感谢新的 NHibernate LINQ 提供者,我现在可以在模式下工作 这不仅更安全,而且 也更具可读性。

在查询之前和之后查看这些 并自己判断:

之前(标准 API)

   1: public IList<Call> GetCallsByDate(DateTime beginDate, int interpreterId)
   2: 
   3:     ICriteria criteria = Session.CreateCriteria(typeof(Call))
   4:         .CreateAlias("Customer", "Customer")
   5:         .Add(Restrictions.Gt("StartTime", beginDate))
   6:         .Add(
   7:            Restrictions.Or(
   8:                 Restrictions.Lt("EndTime", DateTime.Now), Restrictions.IsNull("EndTime")
   9:                 )
  10:             )
  11:         .Add(Restrictions.Eq("Interpreter.Id", interpreterId))
  12:         .AddOrder(Order.Desc("StartTime"))
  13:         .AddOrder(Order.Desc("Customer.Name"));
  14:
  15:     return criteria.List<Call>() as List<Call>;
  16: 

之后(LINQ to NHibernate)

   1: public IList<Call> GetCallsByDateWithLinq(DateTime beginDate, int interpreterId)
   2: 
   3:     var query = from call in Session.Linq<Call>()
   4:                     where call.StartTime > beginDate
   5:                         && (call.EndTime == null || call.EndTime < DateTime.Now )
   6:                         && call.Interpreter.Id == interpreterId
   7:                     orderby call.StartTime descending, call.Customer.Name
   8:                     select call;
   9:
  10:     return query.ToList();
  11: 

【讨论】:

【参考方案6】:

如果我没记错的话,Linq2Sql 不能很好地支持多对多表关系

http://www.chrisbrandsma.com/2007/08/linq-to-sql-many-to-many-tables-and.html

【讨论】:

以上是关于将 Linq 中的 NHibernate 应用程序重写为 SQL的主要内容,如果未能解决你的问题,请参考以下文章

LINQ to nHibernate - 将 SQL“NOT IN”表达式转换为 LINQ

用于 NHibernate 的 Linq 和预加载的 fetch 模式

linq查询的问题

NHibernate3剖析:Query篇之NHibernate.Linq增强查询

如何在 Hql 中执行 ThenFetch 以及如何分解 nhibernate linq 中的许多连接?

我在哪里可以获得用于 NHibernate 的 Linq?