我现在正在使用 NHibernate 一段时间,最后遇到了一个问题,我既找不到答案,也找不到其他人似乎有这个问题。环境是 NHibernate 3.3.1.4000 和 NHibernate.Envers 1.4 用于保存历史。
我有以下类型的数据库表/实体类:
public class ProcedureStep
{
public virtual int Id { get; protected internal set; }
public virtual Procedure ParentObject { get; set; }
public virtual int StepNo { get; set; }
public virtual string Name { get; set; }
}
与映射:
public class ProcedureStepMap : ClassMap<ProcedureStep>
{
public ProcedureStepMap()
{
Table("ProcedureStep");
Id(x => x.Id);
References(x => x.ParentObject).Not.Nullable().UniqueKey("UK_PO_SN");
Map(x => x.StepNo).Not.Nullable().UniqueKey("UK_PO_SN");
Map(x => x.Name).Not.Nullable();
}
}
我们有一个包含过程步骤列表的父对象。用户现在可以添加、删除或修改不同的步骤。一种“修改”是使用按钮在步骤列表中向上或向下移动所选项目来改变程序步骤的顺序。
让我们举一个具体的例子:
该方案是 4 个过程步骤 1-4 的列表:
(1) Aaaa
(2) Bbbb <--
(3) Cccc
(4) Dddd
用户选择第二项“Bbbb”并按下“Up”按钮,得到:
(1) Bbbb <--
(2) Aaaa
(3) Cccc
(4) Dddd
在代码中,我现在想做类似的事情
Begin Transaction
1) Set "Aaaa" to StepNo = 0
2) Set "Bbbb" to StepNo = 1
3) Set "Aaaa" to StepNo = 2
End Transaction
但是现在 NHibernates 开始发挥作用了。NHibernate 在提交事务时对第 1 步一无所知,因此尝试对数据库仅使用 2 个更新命令(第 2 步和第 3 步),由于 StepNo 列的独特性,这不起作用。在第 1 步之后添加 session.flush() 不会改变该行为的任何内容(我可以理解,因为我们在事务中)。
下一个想法只是session.CreateQuery("update...").ExecuteUpdate()
用来对数据库进行更改,它工作正常,但正在围绕 Envers 工作,让我没有此更改的历史记录(再次很容易理解,因为 sql 刚刚传递)。
但是,在一次交易中拥有一切并拥有 Envers 的历史,进行这种改变的正确方法是什么?难道不是让“StepNo”列独一无二是让它工作的唯一方法吗?不希望丢失列的唯一性,因为正确的排序和数据库确保这一点很重要,这将是一个很大的帮助。
预先感谢您的想法!
[解决方案]:
jbl 和 cremor 似乎有唯一的答案。连同其他一些麻烦点,我们现在决定完全跳过 Envers,并使用一种更专业的方式来进行历史管理,不太通用,更适合我们的需求。如果没有 Envers,则可以使用 sql 命令通过简单的 3 步更新来解决问题。