我在NHibernate中映射了一个实体,并使用SQL时间戳列作为版本号进行乐观并发控制。映射如下所示:
<class name="Entity" optimistic-lock="version" discriminator-value="0">
<id name="id">
<generator class="native" />
</id>
<version name="Version" column="Version" generated="always" unsaved-value="null" type="System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
...
<subclass name="ChildEntity" discriminator-value="1" />
</class>
我正在测试数据库中连续数据在记录的获取和更新之间发生变化时会发生什么。为此,我正在直接针对表中正在由NHibernate更新的记录之一运行更新语句。此直接更新会更改表中记录的版本号。
正如预期的那样,NHibernate托管更新不会发生在特定行上(这很好)。但是,在提交期间不会抛出异常。我预计在提交事务时会发生StaleObjectStateException,以便我可以回滚事务并通知用户。这不是预期的行为吗?我错过了什么吗?
我提交事务的代码如下所示:
_session.BeginTransaction();
...
// load objects in session
IList<ChildEntity> toChange = _session.Find('some condition');
foreach ( var itemToChange in toChange )
{
itemToChange.Status = Status.Updated;
}
...
_session.Transaction.Commit();
这些项目属于同一会话,所有工作都在一次交易中完成。 ChildEntity是Entity基类的子类,它将optimistic-lock设置为version。
答案 0 :(得分:5)
您如何修改数据?仅当NHibernate尝试更新行并且版本号不再相同时,才会抛出StaleObjectException。其他栏目无关紧要。您的测试中是否可能没有更新版本号?
前提是:
一个。用户A&amp; B从版本= 1的数据库中获取对象
SQL:SELECT [object] FROM [TABLE] where id = [id] and Version = 1
B中。用户A更新对象,将版本更改为2
SQL:UPDATE [TABLE] SET [object] (& Set Version = 2) where id = [id] and Version = 1
返回1行更新
℃。用户B尝试更新对象,但获取StaleObjectException作为版本= 1的更新对象(他获得第1步的版本)更新数据库中的0条记录。
SQL:UPDATE [TABLE] SET [object] where id = [id] and Version = 1
返回0行更新并抛出StaleObjectException。
答案 1 :(得分:0)
我的测试似乎不准确。在测试中,我正在做其他事务更新记录后得到的。此其他更新使该行不符合更新条件,因此未尝试更新。当我更改测试以在Get之后进行竞争更新时,则按预期抛出StaleObjectStateException。
很抱歉这个混乱。