我有一个非常直接的映射:
<?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列都保持为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();
}
}
谢谢!
答案 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>
的正确类型吗?
版本号可以是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
列...它始终保持为空。