这会导致StaleStateException异常:
var entity = Session.Load(id);
Session.Evict(entity);
entity.SomePropert = "Something";
entity.Version = Version--;
Session.SaveOrUpdate(entity); // Throws Exception
Run Code Online (Sandbox Code Playgroud)
然而,这不会引发异常.也没有更新行.
var entity = Session.Load(id);
entity.SomePropert = "Something";
entity.Version = Version--;
Session.SaveOrUpdate(entity); // Does not throw Exception,
// but no rows are updated
Run Code Online (Sandbox Code Playgroud)
简短的回答是因为版本是由NHibernate管理的属性.您可以更改它,但忽略您的更改.正如您所发现的,改变操作的一种方法是逐出对象,然后重新附加/保存/更新.驱逐导致NHibernate忘记它的版本值是什么让它从对象中获取它.(我可能在这里过于简单化了.)
此问题之前已经提出过.很多人都会问为什么有人会这样做 - 一个有效的场景是无状态的Web应用程序.每个HTTP请求都会创建自己的NHibernate会话,该请求在请求完成时会死亡.可以请求页面以显示要编辑的对象的部分细节.ID和版本保存在隐藏字段中.在postpack(这是一个新请求,这次仅使用数据),新的NHibernate会话重新加载有问题的对象,应用表单数据(包括版本)中的更改,然后保存对象.在此方案中修改此处的版本是完全有效的.如果其他人在初始请求和回发之间修改了相同的对象,则不应覆盖这些更改.应抛出过时的对象异常,但不会抛出,
我知道有两种方法可以修复这些场景的版本"bug".一个是OP已经说明的驱逐方法.第二种是创建一个NHibernate拦截器来捕获更新操作并手动检查版本.
这里讨论了这个问题和两个解决方案.
https://forum.hibernate.org/viewtopic.php?t=977889
我使用从这里提供的代码修改的拦截器.
我的拦截器的内容看起来略有不同(我使用NHibernate 2.1.2.4000).
private void CheckVersion(object domainObject, object uid)
{
ISessionImplementor sessionImpl = Session.GetSessionImplementation();
IEntityPersister persister = sessionImpl.GetEntityPersister(null, domainObject);
if (persister.IsVersioned)
{
EntityMode mode = Session.GetSessionImplementation().EntityMode;
object version = persister.GetVersion(domainObject, mode);
object currentVersion = persister.GetCurrentVersion(uid, sessionImpl);
if (!persister.VersionType.IsEqual(version, currentVersion))
throw new StaleObjectStateException(persister.EntityName, uid);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1943 次 |
| 最近记录: |