【问题标题】:Fluent NHibernate optimistic lockFluent NHibernate 乐观锁
【发布时间】:2013-06-30 04:00:49
【问题描述】:

我正在尝试使用 fluent nhibernate 配置操作锁定。

那里有很多信息,但似乎没有一个适合我所处的场景。我的班级和地图如下(为简洁而编辑):

实体:

public class EmailGroup : CRUDDomainObject<EmailGroup>
{        
    public virtual string Id { get; set; }
    public virtual MailServer Server { get; set;}
    public virtual string FromAddress { get; set;}
    public virtual string ToAddress { get; set;}
    public virtual long Version { get; set; }    
}

地图:

public class EmailGroupMap : ClassMap<EmailGroup>
{
    public const string TABLE_ID = "EMAILGROUP";

    public const string FIELD_ID = "EMAILID";
    public const string FIELD_MAIL_SERVER = "MAILSERVID";
    public const string FIELD_FROM_ADDRESS = "EMLFROM";
    public const string FIELD_TO_ADDRESS = "EMLTO";
    public const string FIELD_VERSION = "VERSION";

    public EmailGroupMap()
    {
        Table(TABLE_ID);

        Id(x => x.Id)
            .Column(FIELD_ID)
            .Not.Nullable()
            .GeneratedBy.Assigned()
            .Length(12);

        References(x => x.Server)
            .Column(FIELD_MAIL_SERVER)
            .NotFound.Ignore();

        Map(x => x.FromAddress)
            .Column(FIELD_FROM_ADDRESS)
            .Not.Nullable()
            .Length(120);

        Map(x => x.ToAddress)
            .Column(FIELD_TO_ADDRESS)
            .Not.Nullable()
            .Length(1000);

        Version(X => X.Version)
            .Column(FIELD_VERSION)
            .Generated.Always()
            .UnsavedValue("0")
            .Access.Property();

        DynamicUpdate();

        OptimisticLock.Version();
    }
}

在我看来一切都很好,但是当我加载实体并对其进行修改时,版本号不会增加。同样,如果我在会话打开时手动增加版本,我不会收到 StaleObjectException。

这个配置对于​​更有经验的人来说是否有效?如果是这样,我还能错过什么?

更新:

在实现数据库管理的时间戳之后,版本列(当然)正在递增。然而 NHibernate 不会将该行视为乐观锁定。我从 SQL 服务器捕获了更新查询以检查 where 子句(为简洁起见被截断):

exec sp_executesql N'UPDATE [EMAILGROUP] 
SET [EMLDESC] = @EMLDESC, [MAILSERVID] = @MAILSERVID, [EMLFROM] = @EMLFROM, [EMLTO] = @EMLTO, [EMLCC] = @EMLCC, [EMLBCC] = @EMLBCC 
WHERE [EMAILID] = @EMAILID'

【问题讨论】:

  • 您确定没有覆盖该映射部分的约定吗?也许还可以在您的代码中搜索对帮助程序约定的调用,例如OptimisticLock.Is(&lt;something&gt;).
  • 感谢 cremor,虽然没有覆盖映射,但似乎我正在针对错误的对象进行测试,虽然映射存在,但它不是由 hibernate 管理的。将 Generated 更改为 Never 后,锁定工作正常。

标签: nhibernate fluent-nhibernate


【解决方案1】:

Version 和 SQL Server(不确定是否是您的情况)最典型的场景是 sql 类型 timestamp(已过时)或更好的 rowversion。这应该映射到 C# byte[]。所以这些改变应该可以解决它:

1) 服务器上的版本列必须是rowversion(或timestamp)类型。这样的列会自动更新与当前行相关的任何更改。每个表只能存在一个这样的列

2) 实体应如下所示

public class EmailGroup : CRUDDomainObject<EmailGroup>
{        
   ...
   public virtual byte[] Version { get; set; }  

3) 流畅的映射代码应保持原样。做背后的技巧应该是一个流利的映射器的工作。我们需要实现的是这样的:

<version name="Version" generated="always" unsaved-value="null"  type="BinaryBlob">
    <column name="Version" not-null="false" sql-type="timestamp"/>
</version>

请在此处查看更多信息:http://ayende.com/blog/3946/nhibernate-mapping-concurrency

【讨论】:

  • 感谢 Radim,虽然数据库在每次更新时都在此处增加列,但 NHibernate 仍然没有为乐观锁定生成正确的 where 子句,也没有生成过时的对象异常,这让我相信问题出在其他地方。我已经用生成的 SQL 更新了问题。
  • 我看不到更新。但我肯定会建议你,保持服务器上版本的更新。这将确保,即使其他进程(批处理、管理...)会更改数据,版本也会有所不同。
  • 我现在看到更新了。我在映射中的唯一区别是未保存的值,对于二进制 blob,它是 NULL。你能检查一下吗?其他设置对我来说是相同的(我确实希望您使用 rowversion 而不是 long
  • 感谢 Radim,问题现已解决。投票给你,因为我打算使用这种方法是第二阶段。
【解决方案2】:

为什么指定Generated.Always()?这告诉 NHibernate 这不是一个真正的列,而是由数据库计算的。文档:http://nhibernate.info/doc/nh/en/index.html#mapping-generated

删除它,它应该可以工作。

【讨论】:

  • 嗨,cremor,我已经修改了这条线,因为你是对的,它设置不正确。然而它没有任何效果。
  • 这实际上是问题所在,我正在测试一个非托管对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 2011-02-23
相关资源
最近更新 更多