我使用的数据库严重依赖于标识列。但是,由于我们现在已将所有应用程序移至NHibernate,因此我希望使用HiLo,因为似乎建议使用NHibernate。是否有任何策略可以做到这一点,或者需要注意哪些常见问题?
答案 0 :(得分:14)
您需要设置NH使用的表格才能正确创建HiLo值。让Schema Creator根据您的映射定义创建表,根据数据库中id的当前状态设置值。
我相信(您需要验证这一点)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
是数据库中找到的最高ID。 maxLow
是您在映射文件中指定的值。不知道为什么它会增加一个。除法是整数分割,它截断小数位。
答案 1 :(得分:7)
如果这是一个关于将现有应用程序迁移到先前使用过自动ID的hilos的问题,并且其中包含需要迁移的旧数据......那么这将是我最好的选择(尽管不是尝试过!)欢迎!):
如果当然这只解决了标识列的问题,那么如果您将应用程序移动到NHibernate,那么您的架构中可能需要更改的任何其他内容。
答案 2 :(得分:0)
我写了一个脚本(基于Stephans的答案)来修复hilo值(在sql server上) - 它假设你有一个像
这样的hilo表CREATE TABLE [dbo].[HiloValues](
[next_hi] [int] NULL,
[Entity] [varchar](128) NOT NULL
)
您的表的标识列都称为ID。使用要为其生成hilo值的表名称初始化Entity表。运行该脚本将生成一系列更新语句,如下所示:
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
答案 3 :(得分:0)
以下是最近从增量生成器迁移到 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'
答案 4 :(得分:0)
这是一个脚本(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