【问题标题】:Can't save entity because of null version column. NHibernate由于版本列为空,无法保存实体。休眠
【发布时间】:2012-09-13 09:06:07
【问题描述】:

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

<?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 时,很明显版本列无论如何都保持为空。

控制器代码

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();
    }
}

谢谢!

【问题讨论】:

  • 您是否尝试过将“sql-type”设置为“timestamp”并将“unsaved-value”设置为“null”(请参阅​​我的回答)?

标签: c# .net nhibernate concurrency


【解决方案1】:

尝试将 sql-type="timestamp" 添加到版本列映射。例如

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

【讨论】:

    【解决方案2】:

    您确定您使用的&lt;version&gt; 类型正确吗?

    来自NHibernate documentation

    版本号可以是 Int64、Int32、Int16、Ticks、Timestamp、 或 TimeSpan(或其在 .NET 2.0 中的可为空的对应项)。

    【讨论】:

    【解决方案3】:

    无意中找到了一个很明显的解决方案:

    <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 列...它始终保持为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-18
      • 1970-01-01
      • 2015-01-30
      相关资源
      最近更新 更多