asp.net-mvc - 为什么 NHibernate 在使用存储过程进行更新时不反映内存状态?
问题描述
我有一个过程,我有一个 NHibernate 会话,我用它来对数据库运行查询。然后,我遍历结果集合,并且对于每次迭代,使用相同的 NHibernate 会话,我调用 SQL 存储过程(使用CreateSQLQuery()
& ExecuteUpdate()
),最终对该实体的字段执行更新。
当它完成对列表的迭代(并调用 SP x 次)时,如果我直接在 SSMS 中检查数据库,我可以看到每行的 UPDATE 都已应用。
但是,在我的代码中,如果我随后立即再次运行相同的初始查询以检索该实体列表,则它不会反映 SP 对每一行所做的更新——该值仍然为 NULL。
我的应用程序中没有针对 NHibernate 的配置指定任何缓存行为,并且SetCacheMode()
在调用查询时尝试了不同的缓存行为,但似乎没有任何区别 - 我可以直接在数据库中看到的值已经更新,当我重新查询(使用Session.QueryOver()
)数据库(使用同一个会话)时,没有被带回更新。
解决方案
通过调用CreateSQLQuery
(更新数据库,单行或多行无关紧要),实际上您正在执行DML 样式的操作,它不会更新内存中的状态。
任何调用CreateSQLQuery
或CreateQuery
不会使用/反映跟踪。这些被认为超出了工作单元的范围。
这些操作直接影响底层数据库,忽略任何内存状态。
14.3. DML 风格的操作
正如已经讨论过的,自动和透明的对象/关系映射与对象状态的管理有关。这意味着对象状态在内存中可用,因此直接在数据库中操作(使用 SQL 数据操作语言 (DML) 语句:INSERT、UPDATE、DELETE)数据不会影响内存状态。然而,NHibernate 提供了通过 Hibernate 查询语言 (HQL) 执行的批量 SQL 样式 DML 语句执行的方法。也可以使用 Linq 实现。
他们(可能)处理大量数据。出于性能原因,它们在某些情况下是必需的。有了这些,跟踪就不起作用了;所以是的,内存状态变得无效。你必须小心使用它们。
如果我随后立即再次运行相同的初始查询以检索该实体列表,它不会反映 SP 为每一行所做的更新 - 该值仍然为 NULL。
这是由于第一(会话)级缓存。这始终默认启用,不能使用 禁用ISession
。
当您第一次加载对象时,它会命中数据库。您从数据库中获取对象-循环遍历它们-执行那些不在工作单元中的命令(如上所述)-再次执行相同的查询两次ISession
以在同一实例下加载相同的对象。第二次调用根本没有命中数据库。
它只是从内存中返回实例。由于您的内存中实例根本没有更新,因此您始终会获得原始实例。
要获取更新的实例,请关闭第一个会话并使用新会话重新加载实例。
更多细节请参考:Hibernate Query Cache 是如何工作的
推荐阅读
- c# - 如果超过 1 行,则从表类型插入 SQL Server 失败
- c++ - 如何使用 Visual Studio 2017 为 Win32 构建 SRP?
- react-native - 使用 Ionic、React Native、NativeScript 和 Flutter 捕获“通话结束”事件?
- django - 没有找到 NoReverseMatch URL Django
- python - AttributeError:“元组”对象没有属性“权重”
- cloudera - 黑白 Mapr 与 Cloudera 的区别?
- javascript - 如何使用 jquery 和 mediaelement-and-player.js 动态创建 mediaelement 播放器?
- jquery - 我想通过使用 css 或其他方式向发件人隐藏所有电子邮件地址
- performance - 减少启动播放模式和脚本更新的时间
- wordpress - Wordpress,WooCommerce - 保存产品非常慢