1

我使用 SQL 时间戳列作为版本号在 NHibernate 中映射了一个具有乐观并发控制的实体。映射如下:

<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 基类的子类,它的乐观锁设置为版本。

4

2 回答 2

5

你是如何修改数据的?只有当 NHibernate 尝试更新行并且版本号不再相同时,才会抛出 StaleObjectException。其他列无关紧要。是否有可能在您的测试中您没有更新版本号?

前提是这样的:

A. 用户 A & 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 行

C. 用户 B 尝试更新对象,但获得 StaleObjectException 作为更新对象,版本 = 1(他在步骤 1 中获得的版本)更新了数据库中的 0 条记录。

SQL:UPDATE [TABLE] SET [object] where id = [id] and Version = 1返回 0 行更新并抛出 StaleObjectException。

于 2009-12-01T03:01:56.443 回答
0

看来我的测试不准确。在测试中,我在其他事务更新记录后进行获取。此其他更新使该行不符合更新条件,因此未尝试更新。当我更改测试以在 Get 之后进行竞争更新时,StaleObjectStateException 按预期抛出。

对困惑感到抱歉。

于 2009-12-01T20:00:37.323 回答