Как обменять уникальные, упорядочивающие записи столбцов с помощью NHibernate и Envers?

Я работаю с 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
{
    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» и нажимают кнопку «Вверх», чтобы получить:

(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 и 3), которые не работают, из-за уникального символа столбца StepNo. Добавление session.flush() после шага 1 не меняет ничего такого поведения (вполне понятно для меня, так как мы находимся внутри транзакции).

Следующей идеей было просто использовать session.CreateQuery («update ...»). ExecuteUpdate() , чтобы делать изменения в базе данных, которая работает нормально, но работает вокруг Envers и оставляет меня без запись истории для этого изменения (вполне понятная еще раз, поскольку sql только что передан).

Но каков был бы правильный способ сделать это изменение, имея все в одной транзакции и имеющую историю Envers? Может быть, что уникальная колонка «StepNo» не единственная возможность заставить ее работать? Потеря уникального символа столбца не будет желательна, так как важно иметь порядок заказа и иметь базу данных, обеспечивающую это, было бы большой помощью.

Спасибо заранее за ваши идеи!

[Решение]:

Кажется, что у jbl и cremor есть только ответы. Вместе с некоторыми другими проблемами мы теперь решили полностью пропустить Envers и использовать более специализированный способ ведения истории, менее общий, более адаптированный к нашим потребностям. Без Envers эта проблема может быть решена простым трехэтапным обновлением с использованием команд sql.

3
nl ja de
Вы правы @JokoFacile, похоже, что это невозможно без использования специального оператора SQL stackoverflow.com/q/1766057/1236044
добавлено автор jbl, источник
Если вы используете sqlserver, я боюсь, что он не поддерживает отложенные ограничения. Одно дело может быть в двух транзакциях: первая транзакция увеличивает весь индекс элемента с размером коллекции. Вторая транзакция возвращает предметы назад и в нужном месте. Но это кажется довольно искусственным, производительность жадным, создаст шум в вашей системе управления версиями ...
добавлено автор jbl, источник
как отображается коллекция? Как набор, сумка или список? Если вы используете список - вам нужен «stepno» вообще на дочернем объекте?
добавлено автор Roger, источник
@Roger: он отображается как список, извините, забыл опубликовать эту часть. Но я не понимаю, что делает разницу в соответствии с наличием столбца базы данных для StepNo, это просто не понадобится в объектной модели. Но исключение происходит из базы данных, а не объектной модели. Но я более подробно рассмотрю это.
добавлено автор JokoFacile, источник
@jbl: ... но конкретный SQL, использующий CreateQuery, будет работать вокруг Envers, поэтому это тоже не работает, что является одной из проблем.
добавлено автор JokoFacile, источник

1 ответы

Если ваша база данных поддерживает отложенные ограничения, я бы их использовал.

0
добавлено
@JokoFacile Я так не думаю. Но это должно быть возможно с помощью : nhforge.org/doc/nh/en/index.html#mapping-database-object
добавлено автор cremor, источник
Большое спасибо, на самом деле это, похоже, способ, чтобы все работало и поддерживало проверку базы данных. Есть ли возможность заставить NHibernate генерировать противоречие в качестве отложенного ограничения?
добавлено автор JokoFacile, источник
Для быстрого тестирования это, похоже, работает, но только с Oracle, SQLite используется в целях развития до сих пор и не поддерживает отложенный уникальный ключ, а только отложенные ограничения внешнего ключа. Но это, по крайней мере, было бы решением для конечной системы производства. Я оставлю вопрос открытым чуть больше, может быть, возникнет другая идея ...
добавлено автор JokoFacile, источник
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot