Есть ли практический способ перехода от столбцов идентификаторов к ключам hilo?
Я работаю с базой данных, которая сильно зависит от столбцов идентификаторов. Однако, поскольку мы переместили все приложения в NHibernate, я хотел изучить использование HiLo, как представляется, рекомендуется с помощью NHibernate. Существуют ли какие-либо стратегии для этого или какие-то общие проблемы, на которые нужно следить?
Ответы
Ответ 1
Если это вопрос о переносе существующего приложения на hilos, который ранее использовал идентификаторы auto, и у него есть старые данные, которые нужно перенести... тогда это было бы лучше всего (не пробовал, хотя!) - комментарии добро пожаловать!):
- Измените идентификаторы типов столбцов на bigints
- узнать наивысшее значение id в настоящее время в любой таблице.
- Установите значение "next-high" в исходной таблице hilo на значение, превышающее значение, указанное в идентификаторах
Если в этом курсе рассматриваются только проблемы с столбцом идентификации, а не что-либо еще в вашей схеме, которые могут потребоваться изменить, если вы перемещаете приложение в NHibernate.
Ответ 2
Вам нужно настроить таблицу, используемую 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
- это значение, указанное в файле сопоставления. Нет идеи, почему она увеличивается на единицу. Разделение представляет собой целочисленное деление, которое усекает десятичные знаки.
Ответ 3
Я написал script (на основе ответа Stephans) для фиксации значений hilo (на сервере sql) - он предполагает, что у вас есть таблица hilo, например
CREATE TABLE [dbo].[HiloValues](
[next_hi] [int] NULL,
[Entity] [varchar](128) NOT NULL
)
И ваши столбцы идентификации таблицы называются ID. Инициализируйте таблицу Entity с именами таблиц, которые вы хотите сгенерировать значения hilo для. Запуск script приведет к созданию ряда операторов обновления, подобных этой:
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
Ответ 4
Вот пример недавней миграции из генератора increment в MultipleHiLoPerTableGenerator (например, для хранения больших значений для всех сущностей используется одна таблица).
Мое приложение использует файлы сопоставления Hibernate 3 + (.hbm.xml). Моя база данных - MySQL (innoDB + auto increment 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'
Ответ 5
Здесь script (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