为什么 NHibernate 在使用存储过程进行更新时不反映内存中的状态?

Why NHibernate not reflecting in-memory state when updates made with stored procedure?

我有一个 NHibernate 会话,我用它来 运行 对数据库进行查询。然后我遍历结果集合,对于每次迭代,使用相同的 NHibernate 会话,我调用 SQL 存储过程(使用 CreateSQLQuery() & ExecuteUpdate()),它最终执行更新该实体的字段。

当它完成对列表的迭代(并调用 SP x 次)时,如果我直接在 SSMS 中检查数据库,我可以看到已应用每一行的更新。

但是,在我的代码中,如果我立即再次 运行 相同的初始查询以检索该实体列表,它不会反映 SP 对每一行所做的更新 - 值为仍然是 NULL。

我没有在我的应用程序中针对 NHibernate 配置指定任何缓存行为,并且在调用查询时尝试了不同的 SetCacheMode(),但似乎没有任何区别 - 我的值可以直接在数据库中看到已经更新,当我重新查询(使用Session.QueryOver())数据库(使用相同的会话)时没有被带回更新。

通过调用CreateSQLQuery(更新数据库,单行或多行都无所谓),实际上你在做DML-style operation,它不会更新内存中的状态。
任何对 CreateSQLQueryCreateQuery 的调用都不会 use/reflect 跟踪。这些被认为超出了工作单元的范围。
这些操作直接影响底层数据库,忽略任何内存中状态。

14.3. DML-style operations
As already discussed, automatic and transparent object/relational mapping is concerned with the management of object state. This implies that the object state is available in memory, hence manipulating (using the SQL Data Manipulation Language (DML) statements: INSERT, UPDATE, DELETE) data directly in the database will not affect in-memory state. However, NHibernate provides methods for bulk SQL-style DML statement execution which are performed through the Hibernate Query Language (HQL). A Linq implementation is available too.

他们(可能)处理大量数据。出于性能原因,它们在某些情况下是必需的。有了这些,跟踪就不起作用了;所以是的,内存中的状态变得无效。你必须小心使用它们。

if I then immediately run the same initial query again, to retrieve that list of entities, it does not reflect the updates that the SP made for each row - the value is still NULL.

这是由于一级(会话)级缓存。默认情况下始终启用,无法使用 ISession.

禁用

当您首先加载对象时,它是一个数据库命中。您从数据库 中获取对象 - 遍历它们 - 执行那些不在工作单元中的命令(如上所述) - 然后 再次 执行相同查询 两次 以在同一 ISession 实例下加载相同的对象。第二次调用 根本没有访问数据库

它只是 return 内存中的实例。由于您的内存中实例根本没有更新,因此您始终获得原始实例。

要获取更新的实例,请关闭第一个会话并使用新会话重新加载实例。

更多详情请参考:How does Hibernate Query Cache work