Есть ли практический способ перехода от столбцов идентификаторов к ключам 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