我正在尝试使用流畅的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'
答案 0 :(得分:2)
Version
和SQL Server最常见的scneario(不确定这是否是您的情况)是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
答案 1 :(得分:2)
为什么指定Generated.Always()
?这告诉NHibernate这不是一个真正的列,而是由数据库计算。文档:http://nhibernate.info/doc/nh/en/index.html#mapping-generated
删除它,它应该工作。