nhibernate - para - como poner la ñ en teclado americano
¿Existe alguna forma práctica de migrar de las columnas de identidad a las teclas de las letras? (5)
Trabajo con una base de datos que depende en gran medida de las columnas de identidad. Sin embargo, como ahora hemos trasladado todas las aplicaciones a NHibernate, quería estudiar el uso de HiLo, ya que parece ser recomendado con NHibernate. ¿Hay alguna estrategia para hacer esto, o algún problema común a tener en cuenta?
Si esta es una pregunta acerca de migrar una aplicación existente a hilos que previamente usaba identificadores automáticos, y tiene datos antiguos que deben migrarse ... entonces esta sería mi mejor opción (¡aunque no lo intenté! - ¡Bienvenidos los comentarios!) :
- Cambie los ID de los tipos de columnas a BIGINT
- descubra el valor de identificación más alto actualmente en cualquier tabla.
- Establezca el valor "siguiente-alto" en la tabla de origen del hilo en un valor superior al que encontró en los ID
Por supuesto, esto solo resuelve problemas con la columna de identidad, no con cualquier otra cosa en su esquema que deba cambiar si mueve una aplicación a NHibernate.
Escribí un guión (basado en la respuesta de Stephans) para fijar los valores de los hilos (en el servidor SQL) - se supone que tienes una tabla de hilos como
CREATE TABLE [dbo].[HiloValues](
[next_hi] [int] NULL,
[Entity] [varchar](128) NOT NULL
)
Y las columnas de identidad de su tabla se llaman ID. Inicie la tabla Entidad con los nombres de tabla para los que desea generar los valores del hilo. La ejecución del script generará una serie de declaraciones de actualización como esta:
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''
Aquí está
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
Necesita configurar la tabla utilizada por NH para crear valores HiLo correctamente. Deje que Schema Creator cree la tabla de acuerdo con sus definiciones de mapeo, establezca los valores de acuerdo con el estado actual de los identificadores en su base de datos.
Creo (es necesario verificar esto) que los valores generados por el hilo se calculan mediante:
hilo-id = high-value * max_lo + low-value
Mientras que el valor alto se almacena en la base de datos, max_low se define en el archivo de mapeo y el valor bajo se calcula en tiempo de ejecución.
NHibernate también necesita su propia conexión y transacción para determinar e incrementar el alto valor. Por lo tanto, no funciona si la conexión proporciona la conexión.
Aún puede usar seqhilo
, NH usa una secuencia de base de datos para crear los próximos valores altos y no necesita una conexión separada para hacerlo. Esto solo está disponible en bases de datos que admiten secuencias, como Oracle.
Corrección:
Mientras tanto, tuve que implementarlo yo mismo (antes, era solo teoría :-). Entonces vuelvo a compartir los detalles.
La fórmula es:
next_hi = (highest_id / (maxLow + 1)) + 1
next_hi
es el campo en la base de datos que necesita actualizar. highest_id
es la identificación más alta que se encuentra en tu base de datos. maxLow
es el valor que especificó en el archivo de mapeo. No idea por qué se incrementa en uno. La división es una definición entera que trunca los decimales.
Aquí hay una secuencia de comandos (MS SQL) que llenará la tabla HiLo (Nombre, Valor) con todos los siguientes números altos para todas las tablas en la base de datos actual:
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
Aquí hay una muestra de una migración reciente desde el generador de incrementos al MultipleHiLoPerTableGenerator (por ejemplo, una sola tabla se usa para almacenar valores altos para cada entidad).
Mi aplicación está usando archivos de mapeo Hibernate 3+ (.hbm.xml). Mi base de datos es MySQL (innoDB + auto incremento pk).
Paso 1 : reemplace la configuración de su generador en sus archivos .hbm. Reemplazar:
<generator class="increment" />
Por
<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>
Paso 2 : crea una nueva tabla para almacenar los valores altos
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;
Paso 3 : llene los valores altos iniciales de acuerdo con los datos existentes usando la siguiente pieza de SQL. Supongo que aquí se usa el mismo valor de max_lo
para cada tabla.
INSERT INTO hilo_values SELECT TABLE_NAME, ((AUTO_INCREMENT DIV (1000 + 1)) + 1) FROM information_schema.tables WHERE table_schema = ''yourdbname''