Существует ли практичный способ перехода от столбцов идентификации к ключам HILO?
Я работаю с базой данных, которая сильно зависит от столбцов идентификации. Однако, поскольку теперь мы переместили все приложения в NHibernate, я хотел изучить использование HiLo, что, как представляется, рекомендуется для NHibernate. Есть ли какие-либо стратегии для этого или какие-то общие проблемы, на которые стоит обратить внимание?
5 ответов
Если это вопрос о переносе существующего приложения в hilos, в котором ранее использовались автоматические идентификаторы, и в котором есть старые данные, которые необходимо перенести... то это был бы мой лучший выбор (хотя не пробовал! - комментарии приветствуются!):
- Измените идентификаторы типов столбцов на bigints
- узнать наибольшее значение идентификатора в настоящее время в любой таблице.
- Установите значение 'next-high' в исходной таблице hilo на значение выше, чем вы нашли в идентификаторах
Если, конечно, это решает только проблемы со столбцом идентификаторов, а не что-либо еще в вашей схеме, которое может потребоваться изменить, если вы перемещаете приложение в NHibernate.
Вам необходимо настроить таблицу, используемую NH, для правильного создания значений HiLo. Позвольте Schema Creator создать таблицу в соответствии с вашими определениями сопоставления, установить значения в соответствии с текущим состоянием идентификаторов в вашей базе данных.
Я считаю (вы должны это проверить), что значения, генерируемые hilo, рассчитываются по формуле:
hilo-id = high-value * max_lo + low-value
В то время как старшее значение хранится в базе данных, max_low определяется в файле отображения, а низкое значение вычисляется во время выполнения.
NHibernate также нуждается в своем собственном соединении и транзакции, чтобы определить и увеличить высокое значение. Поэтому он не работает, если соединение предусмотрено приложением.
Вы все еще можете использовать seqhilo
NH использует последовательность базы данных для создания следующих больших значений и для этого не требуется отдельное соединение. Это доступно только для баз данных, которые поддерживают последовательности, такие как Oracle.
Исправление:
Между тем мне пришлось самому это реализовать (раньше это была просто теория:-). Поэтому я возвращаюсь, чтобы поделиться деталями.
Формула:
next_hi = (highest_id / (maxLow + 1)) + 1
next_hi
поле в базе данных, которое необходимо обновить. highest_id
самый высокий идентификатор, найденный в вашей базе данных. maxLow
это значение, которое вы указали в файле сопоставления. Не знаю, почему он увеличивается на единицу. Деление является целочисленным делением, которое усекает десятичные знаки.
Я написал скрипт (на основе ответа Стефана) для исправления значений hilo (на сервере sql) - он предполагает, что у вас есть таблица hilo, например
CREATE TABLE [dbo].[HiloValues](
[next_hi] [int] NULL,
[Entity] [varchar](128) NOT NULL
)
И столбцы идентификации вашей таблицы все называются ID. Инициируйте таблицу Entity с именами таблиц, для которых вы хотите сгенерировать значения hilo. Выполнение скрипта сгенерирует серию операторов обновления, подобных этой:
UPDATE hv
SET next_hi = Transactions.ID/(10 + 1) + 1
FROM HiloValues hv
CROSS JOIN (SELECT ISNULL(Max(ID), 0) as id FROM Transactions) as Transactions
WHERE hv.entity = 'Transactions'
Вот
DECLARE @scripts TABLE(Script VARCHAR(MAX))
DECLARE @max_lo VARCHAR(MAX) = '10';
INSERT INTO @scripts
SELECT '
UPDATE hv
SET next_hi = ' + Entity + '.ID/(' + @max_lo + ' + 1) + 1
FROM HiloValues hv
CROSS JOIN (SELECT ISNULL(Max(ID), 0) as id FROM ' + entity + ') as ' + entity + '
WHERE hv.entity = ''' + entity + '''' as script
FROM HiloValues WHERE Entity IN (SELECT name from sys.tables)
DECLARE curs CURSOR FOR SELECT * FROM @scripts
DECLARE @script VARCHAR(MAX)
OPEN curs
FETCH NEXT FROM curs INTO @script
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @script --OR EXEC(@script)
FETCH NEXT FROM curs INTO @script
END
CLOSE curs
DEALLOCATE curs
Вот пример недавней миграции с генератора приращений на MultipleHiLoPerTableGenerator (например, одна таблица используется для хранения высоких значений для всех сущностей).
Мое приложение использует файлы отображения Hibernate 3 + (.hbm.xml). Моя база данных MySQL (innoDB + автоматическое увеличение pk).
Шаг 1: замените настройки вашего генератора в ваших.hbm файлах. Заменить:
<generator class="increment" />
От
<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
<param name="table">hilo_values</param>
<param name="primary_key_column">sequence_name</param>
<param name="value_column">sequence_next_hi_value</param>
<param name="max_lo">1000</param>
</generator>
Шаг 2: создайте новую таблицу для хранения высоких значений
CREATE TABLE IF NOT EXISTS `hilo_values` (
`sequence_name` varchar(255) NOT NULL,
`sequence_next_hi_value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Шаг 3: заполните начальные высокие значения в соответствии с существующими данными, используя следующий фрагмент SQL. Я предполагаю, что то же самое max_lo
значение используется для каждой таблицы.
INSERT INTO hilo_values SELECT TABLE_NAME, ((AUTO_INCREMENT DIV (1000 + 1)) + 1) FROM information_schema.tables WHERE table_schema = 'yourdbname'
Вот скрипт (MS SQL), который заполнит таблицу HiLo(Name,Value) всеми следующими старшими числами для всех таблиц в текущей базе данных:
declare tables cursor for
select
Table_Schema,
Table_Name
from
information_schema.tables
where
Table_Schema = 'dbo'
and
Table_Type = 'BASE TABLE'
and
Table_Name <> 'HiLo'
and
right (Table_Name, 1) <> '_'
declare @table_schema varchar(255)
declare @table_name varchar(255)
truncate table HiLo
open tables
fetch next from tables into @table_schema, @table_name
while (@@fetch_status = 0)
begin
declare @sql as nvarchar(max)
declare @max_id as int
set @sql = 'select @max_id = max(Id) from [' + @table_schema + '].[' + @table_name + ']'
exec sp_executesql @sql, N'@max_id int output', @max_id output
declare @max_low as int
set @max_low = 1000
declare @next_high as int
set @next_high = isnull (@max_id / @max_low + 1, 0)
--select @table_name, @max_id, @next_high
insert into HiLo (Name, Value) values (@table_schema + '.' + @table_name, @next_high)
fetch next from tables into @table_schema, @table_name
end
close tables
deallocate tables
select * from HiLo