nHibernate 不加载第三级属性(不可刷新缓存)

Posted

技术标签:

【中文标题】nHibernate 不加载第三级属性(不可刷新缓存)【英文标题】:nHibernate not loading third-level properties (non-flushable caching) 【发布时间】:2010-01-13 18:03:43 【问题描述】:

我开始将基于 Sharepoint 的 ASP.NET 项目中的一些预先存在的 nHibernate 代码从急切加载和每个数据库命中的新会话切换到延迟加载和 HTTP 请求期间的会话,并开始运行一个问题。

当我们在这个系统中创建一个项目时,有一些由下拉列表填充的多对一关系。这为我们提供了 ID,这足以保存到数据库中。

为了执行一些保存后的任务,例如电子邮件通知,然后我们将相同的项目加载回来,这之前会填充整个对象树。

但是,自从更改为延迟加载和会话与整个请求的生命周期以来,我们一直在从 Item 下面的属性中获取 NullReferenceExceptions,这些属性神秘地为 null。

我们通过 nHibernate 将项目加载到 changedItem 中。失败的调用是:

changedItem.PaperMedia.FormsAnalyst.User.Contact.Name

PaperMedia 已完全填充,但 FormsAnalyst 上的所有内容都为空,除了 ID。

这与我们保存时的状态相同,因此导致此问题的一个可能原因是项目被缓存并简单地检索,因此 nHibernate 不知道数据库中的实际值。但是,我正在提交事务,并在保存和后续加载之间在会话上显式调用 Flush(),所以如果是这种情况,那么 Commit() 和 Flush() 都不会对缓存产生任何影响。

我已将相关 hbm.xml 文件中的这些属性更改为lazy="false",并为所有这些属性设置了 SetFetchMode FetchMode.Eager,但没有任何效果。

我也在考虑 max_fetch_depth 作为问题。如果我在会话上调用 Refresh(changedItem),它没有效果。但是,如果我调用 Refresh(changedItem.PaperMedia),它将一直填充到 Name。这似乎将 max_fetch_depth 视为问题,但我仍然尝试增加它,将其设置为 hibernate.cfg.xml 中的 6 以及配置实例上的 SetProperty("max_fetch_depth", "6")在创建会话工厂时,这些也没有效果。

我不知道还能尝试什么。

有人见过这样的事情吗?我是 nHibernate 的新手,所以它可能很简单......

编辑:

看起来缓存确实是问题所在。在会话实例上调用 Clear() 可修复此行为。

所以现在的问题变成了,为什么 Flush() 不会更新缓存的项目?这正是我认为它的目的。

【问题讨论】:

发生这种情况时,FormsAnalyst 是生成的代理类吗?我没有使用 max_fetch_depth 但我认为它只适用于急切加载。 是的,您可能是对的,但不,此时它是一个实际的 UserAnalyst 对象,因为我急切地加载它以试图解决问题。在我开始弄乱我的 hbm.xml 文件和我的获取模式等之前,我相信它是一个代理对象,但我还没有找到一个除了 NullReferenceException 之外的组合。 【参考方案1】:

我认为 Flush() 仅用于将更改发送到数据库...如果此时它们在内存中,它将使用引用的对象更新缓存。因此,您可以使用另一个会话或 Clear()... 或首先填充 FormsAnalyst。

【讨论】:

好吧,首先填充孩子并不是一个好选择,因为它是用户正在创建的新项目,所以我必须将所有额外数据发送给客户端并拥有它们把它退回。 Clear() 在这种情况下运行良好,但在调用 Clear() 之后会导致该会话的未来延迟加载出现问题。我现在已经使用了 hacky Refresh(changedItem.PaperMedia),但我仍然感到困惑。如果 Flush() 仅用于将更改发送到数据库,它是否永远不会返回更改?

以上是关于nHibernate 不加载第三级属性(不可刷新缓存)的主要内容,如果未能解决你的问题,请参考以下文章

Nhibernate:只读属性导致急切加载

nhibernate 可以在没有代理的情况下进行延迟加载吗?

NHibernate第三方二级缓存bug

数据库范式 / 事务

NHibernate 可以设置非公共属性吗?

2017-6-7AJAX异步刷新 省市区 三级联动