То, что я сейчас собираюсь описать, иначе как грязный хак назвать нельзя. Но жизнь сложная штука, и иногда приходится изворачиваться как уж, чтобы добиться своего. А добиться я пытаюсь вот чего: чтобы NHibernate не ломал семантику Unit of Work при работе с классами, Id которых генерится Identity счетчиком в SQL Server.
Прежде всего, советую ознакомиться с историей вопроса: о вреде Identity генераторов, еще о вреде и мнение в законе. Проблема Identyity генератора в том, что он не может получить Id, не вставив запись в таблицу, а без Id сущность нельза ассоциировать с NHibernate сессией, поэтому как только мы пытаемся связать объект с сессией, он тут же попадает в базу. Отсюда вырастают огромные проблемы в длинных бизнес транзакциях, когда все действия с БД атомарны и выполняются в отдельных БД транзакциях, а сама бизнес операция растянута по времени. Так вот откат бизнес транзакции будет невозможен в случае использования Identity генератора. А это как раз мой случай. Но, как я уже написал выше решение есть, но это грязный хак.
Итак. Прекратив ныть, про хак, перехожу к сути. Мне надо:
- вставлять свои значения в поля Identity;
- получать адекватные значения для Identity поля;
Вооружившись этим знанием я нарисовал следующую схему:
Решение, как следует из картинки состоит из 3х частей:
- Custom Id generator, который я назвал ORMIdentityGenerator;
- PreInsert listener, для отключения автоинкрементного поля;
- PostInsert listener, для его включения назад;
Следуя agile принципу KISS - keep it simple, stupid! я всего лишь конфигурирую его минимальным INSERT выражением, которое можно исполнить, не повредив базу и не вызвав нарушений целостности.
PreInsert
PostInsert
Вот и все. Теперь я могу спокойно редактировать объект в длинной сессии и откатывать изменения, когда потребуется. PS Простите ребята, гаджетом для вставки кода пока не обзавелся. Удачи!