2

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

<?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 action)都会SqlServer引发异常,其中指出:

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

所以insert会被还原。

最初的问题已解决

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

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

签入时,SQLServer很明显 Version 列无论如何都保持为空。

控制器代码

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

谢谢!

4

3 回答 3

4

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

<version name="Version" generated="always" unsaved-value="null" type="BinaryBlob">
    <column name="Version" not-null="false" sql-type="timestamp"/>
</version>
于 2012-09-17T09:35:44.247 回答
0

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

来自NHibernate 文档

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

于 2012-09-13T10:52:53.323 回答
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列......它总是保持为空。

于 2012-09-14T05:20:26.840 回答