我正在研究一些使用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
的{{1}}属性。 (我假设这是级联更新)
MarketOrder
填充了代理,因为它是从无状态会话加载的,所以无法访问。
果然,如果我从常规会话加载而不是无状态会话,那么一切正常。该解决方案将导致生产中的性能损失,但我宁愿避免它。
我可以将Owner
设置为不延迟加载,但对于所有类似的情况,这不是一个实用的解决方案。
这个问题的答案:NHibernate: proxies cannot be fetched by a stateless session error message。建议将问题属性作为初始加载的一部分来获取,但这看起来非常浪费。我只想更新主对象上的一些属性,为什么我还要加载所有对象的子引用?
我想要的是NHibernate意识到只有主Owner
对象发生了变化,而且没有费心将更新级联到MarketOrder
。事实上,现在我考虑一下,我认为无状态会话本来应该是级联更新吗?
所以任何人都知道这里发生了什么以及如何解决它?