【问题标题】:How can I solve this NHibernate Querying in an n-tier architecture?如何在 n 层架构中解决此 NHibernate 查询?
【发布时间】:2012-10-05 21:29:24
【问题描述】:

我在尝试将 NHibernate 与我的服务层分离时遇到了困难。我的架构如下所示:

web -> 服务 -> 存储库 -> nhibernate -> db

我希望能够从我的服务层和可能的 Web 层生成休眠查询,而这些层不知道它们正在处理什么 orm。目前,我在我的所有存储库中都有一个 find 方法,它接受 IList<object[]> criteria。这使我可以从架构中的任何位置传递一个标准列表,例如new object() {"Username", usernameVariable};。 NHibernate 接受它并创建一个新的 Criteria 对象并添加传入的标准。这适用于从我的服务层进行的基本搜索,但我希望能够传入我的存储库转换为 NHibernate 标准的查询对象。

真的,我很想实现类似这个问题中描述的东西:Is there value in abstracting nhibernate criterion。我只是没有找到任何关于如何实现这样的东西的好资源。该问题中描述的方法是一种好方法吗?如果是这样,任何人都可以提供一些关于如何实施这种解决方案的指示吗?

【问题讨论】:

标签: c# nhibernate onion-architecture


【解决方案1】:

抽象掉 ORM 将:

  • 带来大量重新定义其 API 的工作
  • 无法优化/批量访问数据库
  • 让理解执行的查询变得更加困难
  • 将导致大量的 SELECT N+1

而且价值很小:交换 ORM 框架的模糊选项很可能会有很多其他问题

  • 缺少功能
  • 在实现上的细微差别
  • 学习曲线

更新:经验

我曾经参与实现现有 DAL 抽象的新提供者。它最终表现不佳,引入了很多错误,错误处理一团糟,有时使用陈旧数据,因为应用程序采用默认实现。原因:

  • 缓存不知道上下文
  • 缓存实现有不同的语义
  • 批处理 API 差异太大而无法抽象
  • 错误是特定于实现的(例如,FileNotFound -> FilesearchDialog 对于基于 tcp/ip 的数据库是无用的)
  • 错误恢复是不同的(每个实现都有自己的一组可以从中恢复的错误)
  • 锁定机制不同
  • SQL 数据库中没有一致的更改事件
  • 嵌套事务
  • 模型类中的默认实现流血
  • 重新实现所有抽象的 Queryies 需要大量工作,并引入了很多复制粘贴错误
  • 不明确说明顺序的查询将在不同的实现中返回不同的排序结果

对应用程序进行了大量重构:

  • 去除只​​有一种实现提供的功能
  • 每个实现的缓存管理
  • 由于瞬态数据导致的包装器身份问题
  • 很难在两个数据存储上实现查询

补充要点:

  • 通过抽象 DAL 迁移数据非常慢
  • 实现另一个实现将永远不会发生,因为上述问题太昂贵了(在提到的场景中,我们开始慢慢地重新实现整个项目)
  • 很难实现 DAL API 的正确语义,因为在纯 API 中没有使用上下文

(业务任务的)移植在 IMO 中的痛苦会小得多,因为我们为少数人做了这件事,因为性能原因。

更新 2:经验 2:尝试从 NHibernate 移植到 EntityFramework 时遇到障碍(使用 NH 实现,但无法在合理时间内使用 EF 4)

  • 嵌套事务
  • 枚举支持
  • compositeId 引用(如何去掉referenceIds)
  • 组件中的引用
  • 读取批处理 (Futures),方便页面 + 一次计数
  • 映射 CultureInfo(IUserType 支持)

【讨论】:

  • 为了使这个答案完整,你真的应该提供一些cons 来避免将 ORM 抽象掉,比如 PITA 测试
  • testlist.ForEach(e => session.Save(e));session.Flush();session.Clear();var mock = new Moq<SomeRepository>().Call(s => s.GetSomeThing(...)).Returns(testlist).Object;没有太大区别
  • 第一个是否命中数据库?我自己不是想成为一个 PITA,但很好奇你是如何处理这个问题的......
  • 这里没有PITA,我很高兴向别人学习。我正在使用SqliteConfiguration.Standard.InMemory(),每个测试都有自己的会话。所以这会影响数据库,但由于所有测试都有自己的内存测试,所以我在速度和隔离方面没有问题。 QueryOnly 测试可以共享同一个会话。默认/测试数据可以通过您编写一次或为每个测试单独数据编写的方法注入。
  • 谢谢,我见过这种方法,但似乎永远无法在测试设置中正确导出架构,最终不得不手动按摩生成的 sql。
【解决方案2】:

感谢您的回复!我明白你在说什么,但这些答案并不能解决我的问题。由于我正在编写的系统状态,我无法更改我的架构。相反,我只是将我的所有 sql/hql/criteria api 查询保留在存储库层内,而不是尝试向我的服务公开某种复杂的查询类。这种方法应该可以正常工作。不过,对于我的下一个架构方法,我将考虑其他答案中提出的观点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-06
    • 2011-01-10
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    相关资源
    最近更新 更多