由于null版本列无法保存实体。 NHibernate的

时间:2012-09-13 09:06:08

标签: c# .net nhibernate concurrency

我有一个非常直接的映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="XXXX.DomainLayer" namespace="XXXX.DomainLayer.Entities">
    <class name="Project" optimistic-lock="version">
        <id name="Id" column="ProjectID" unsaved-value="00000000-0000-0000-0000-000000000000">
            <generator class="guid.comb" />
        </id>
        <version name="Version" generated="always" type="BinaryBlob" />
    <!-- poperties -->
    </class>
</hibernate-mapping>

相应的实体看起来像这样:

public abstract class AbstractEntity<T> where T : AbstractEntity<T> {
    public virtual Guid Id { get; protected set; }
    public virtual Byte[] Version { get; set; }

    // other properties, methods
}
public class Project : AbstractEntity<Project>, IAggregateRoot {
    // specific properties, methods
}

我将架构导出到SqlServer。那里的一切都很好。但每次发布表单(create actionSqlServer都会抛出一个异常,说明:

  

无法将值NULL插入“版本”列,...

因此insert会被还原。

解决了初步问题

实际问题是我无法对实体进行编辑 - 我得到了StaleObjectStateException

  

行被另一个事务更新或删除(或未保存的值映射不正确)[XXXX.DomainLayer.Entities.Project#707991d0-07b5-45fc-99ed-a0cc00db108a]

当检入SQLServer时,很明显,无论如何,Version列都保持为null。

控制器代码

public ActionResult Create() {
    return View("Edit", new EditProjectViewModel());
}

[HttpGet]
public ActionResult Edit(Guid id) {
    var project = this.repo.Get(id);
    var model = Mapper.Map<Project, EditProjectViewModel>(project);

    return View(model);
}

[HttpPost, ValidateAntiForgeryToken]
public ActionResult Edit(EditProjectViewModel model) {
    if(ModelState.IsValid) {

       model.InitiatedBy = this.userService.GetUser(some_param);
       model.ProblemContext = BBCode.ToHtml(model.ProblemContext);

       var project = Mapper.Map<EditProjectViewModel, Project>(model);

       if(project.IsTransient) {
           this.repo.Add(project);
       }
       else {
           try {
               this.repo.Update(project);
           }
           catch(NHibernate.StaleObjectStateException e) {
               // Some logic here
           }
       }

       return RedirectToAction("Index", "Home", new { area = "" });
   } // if(ModelState.IsValid) {
   return View(model);
}

存储库Update方法如下:

public void Update(T entity) {
    using(var tx = this.session.BeginTransaction()) {
        /* try { */
            this.session.SaveOrUpdate(entity);
            tx.Commit();
        /* }
        catch(StaleObjectStateException) {
            try {
                entity = this.session.Merge(entity);
                tx.Commit();
            }
            catch(Exception) {
                tx.Rollback();
                throw;
            }
        }
        */
    }
}

DI片

public class DataAccessModule : NinjectModule {
    public override void Load() {
        this.Bind<ISessionFactory>()
            .ToMethod(c => new Configuration().Configure().BuildSessionFactory())
            .InSingletonScope();

        this.Bind<ISession>()
            .ToMethod(ctx => ctx.Kernel.TryGet<ISessionFactory>().OpenSession())
            .InRequestScope();

        this.Bind(typeof(IRepository<>)).To(typeof(Repository<>))
            .InRequestScope();
    }
}

谢谢!

3 个答案:

答案 0 :(得分:4)

尝试添加sql-type =&#34; timestamp&#34;到版本列映射。 E.g。

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

答案 1 :(得分:0)

您确定使用<version>的正确类型吗?

来自NHibernate documentation

  

版本号可以是Int64,Int32,Int16,Ticks,Timestamp,   或TimeSpan(或它们在.NET 2.0中的可空对应物)。

答案 2 :(得分:0)

我偶然发现了一个非常明显的解决方案:

<id name="Id" column="ProjectID" unsaved-value="00000000-0000-0000-0000-000000000000">
        <generator class="guid.comb" />
    </id>
    <version name="Version" generated="always" type="BinaryBlob">
        <column name="Version" not-null="false" />
    </version>
<!-- ... the rest -->

修改

但是这次更改引发了我另一个问题:SqlServer没有更新Version列...它始终保持为空。