質問

I am working with NHibernate for a while now and finally hit a problem, I can neither find an answer, nor anyone else how seemed to have this problem. The environment is NHibernate 3.3.1.4000 and NHibernate.Envers 1.4 for history keeping.

I've got a database table/entity class of the following kind:

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

with the mapping:

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

We have a parent object with a list of procedure steps. The user can now add, delete or modify the different steps. One "modification" is the change of the ordering of the procedure steps using a button to move a selected item up or down in the list of steps.

Let's make a concrete example:

The scenario is a list of 4 procedure steps 1-4:

(1) Aaaa
(2) Bbbb <--
(3) Cccc
(4) Dddd

The users selectes the second item "Bbbb" and presses the "Up" button, to get:

(1) Bbbb <--
(2) Aaaa
(3) Cccc
(4) Dddd

In the code I now thought of doing something like

Begin Transaction
1) Set "Aaaa" to StepNo = 0
2) Set "Bbbb" to StepNo = 1
3) Set "Aaaa" to StepNo = 2
End Transaction

But now NHibernates get's into play. NHibernate does not know anything about step 1 when committing the transaction, and is therefore trying to work with only 2 update commands to the database (steps 2 and 3), which is not working, due to the unique character of the StepNo column. Adding a session.flush() after step 1 is not changing anything to that behaviour (quite understandable to me, as we are within a transaction).

The next idea was just using session.CreateQuery("update...").ExecuteUpdate() to do the changes on the database, which is working fine, but is working around Envers and leaving me without a history record for this change (quite understandable once again, as the sql is just passed on).

But what would be the correct way to do this change, with having everything in one transaction and having the history of Envers? Could it be, that not making the "StepNo" column unique is the only way to get it working? Loosing the unique character of the column would not be wanted, as it is important to have a propper ordering and having the database ensuring this, would be a great help.

Thanks upfront for your ideas!

[Solution]:

jbl and cremor seem to have the only answers. Together with some other points of trouble, we now decided to skip Envers completly and use a more specialized way of doing a history management, less general, more adapted to our needs. With no Envers, the problem could be solved with a simple 3-step update using sql commands.

役に立ちましたか?

解決

If your database supports deferrable constraints I would use them.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top