我正在编写一些代码,这些代码正在使用 NHibernate 进行一些中等繁重的数据处理(是的,我知道,也许不是真正适合这项工作的工具。但这是我必须使用的)
我使用无状态会话来获取前 1000 个对象,如果需要,检查、更新并将它们添加到更新对象列表中。然后我重复接下来的 1000 个对象,直到完成。下面是代码的显着简化版本。
List<MarketOrder> updated = new List<MarketOrder>();
IStatelessSession session = SessionProvider();
int offset = 0;
bool moreToGet = true;
while (moreToGet)
{
var result = session.Query<MarketOrder>().Where(o => o.Owner.ID == currentEntityID && !o.Updated);
var tmp = result.Skip(offset).Take(1000);
foreach (MarketOrder item in data)
{
notUpdated.OrderState = MarketOrderState.Closed;
updated.Add(notUpdated);
}
if (data.Count == pageSize) { offset += pageSize; }
else { moreToGet = false; }
}
然后打开另一个无状态会话以进行批量更新
IStatelessSession session = SessionProvider();
foreach (MarketOrder o in updated) { session.Update(o); }
当我运行单元测试时,出现错误:
Test 'TestProcess_AutoCloseOrder' failed: NHibernate.PropertyValueException : Error dehydrating property value for Data.Models.MarketOrder.Owner
---- NHibernate.PropertyAccessException : Exception occurred getter of Common.Models.ModelBase.Version
-------- System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
------------ NHibernate.SessionException : proxies cannot be fetched by a stateless session
经过一番折腾,我认为错误是因为在更新中,NHibernate 试图访问正在保存的Owner
属性。MarketOrder
(我假设这是级联更新)
Owner
填充了代理,并且由于它是从无状态会话加载的,因此无法访问。
果然,如果我从常规会话而不是无状态会话加载,一切正常。这个解决方案会导致生产中的性能下降,所以我宁愿避免它。
我可以设置Owner
为不延迟加载,但这不是所有类似情况的实用解决方案。
这个问题的答案:NHibernate: proxies cannot be fetched by a stateless session error message。建议获取问题属性作为初始加载的一部分,但这似乎非常浪费。我只想更新主对象的一些属性,为什么还要加载该对象的所有子引用?
我想要的是让 NHibernate 意识到只有主要MarketOrder
对象发生了变化,而不必费心将更新级联到Owner
. 其实现在想来,我没想到Stateless Session根本就不应该级联更新?
所以有人知道这里发生了什么以及我该如何解决它?