将 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 模式
NHibernate3剖析:Query篇之NHibernate.Linq增强查询