.net nhibernate linq-to-sql guid

.net - GUID secuencial en Linq-to-Sql?



nhibernate (6)

Bueno, podrías generar el Guid a mano. Sin embargo, una de las ventajas de un Guid es que no es adivinable, es decir, el registro dado 0000-...-0005 , por lo general, hay poco punto (de un atacante) que comprueba el registro 0000-....-0004 etc. .

Además, ¿re fragmentación? Siempre que tenga un índice no agrupado en estos datos, no estoy seguro de que esto sea un problema. Normalmente no colocaría un índice agrupado en un Guid , por lo que la tabla será un montón (a menos que tenga un índice agrupado por separado, como una IDENTITY int). En ese caso, agregará al final e insertará el nuevo Guid en el índice no agrupado. Sin dolor real

(edit) Un problema de usar el tiempo directamente es que introduces mucho más riesgo de colisión; Guid preocuparse por la creación de Guid ciclo cerrado (es decir, evitar la repetición al crear unos pocos en secuencia), lo que significa sincronización, etc., y se vuelve aún más problemático si varias máquinas trabajan de forma intensiva en paralelo; es probable que obtenga duplicados

Acabo de leer una publicación de blog sobre la capacidad de NHibernate para crear un GUID a partir de la hora del sistema (Guid.Comb), evitando así una buena cantidad de fragmentación de la base de datos. Podría llamarlo el equivalente del lado del cliente al ID secuencial de SQL Server.

¿Hay alguna manera de que yo pueda usar una estrategia similar en mi proyecto Linq-to-Sql (generando el Guid en el código)?


Los COMB se generan de la siguiente manera:

DECLARE @aGuid UNIQUEIDENTIFIER SET @aGuid = CAST(CAST(NEWID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)

Cuál transcrito en C # se vería así:

public static unsafe Guid CombGuid() { Guid guid = Guid.NewGuid(); byte[] bytes = guid.ToByteArray(); long ticks = DateTime.Now.Ticks; fixed( byte* pByte = bytes ) { int* pFirst = (int *)(pByte + 10); short* pNext = (short*)(pByte + 14); *pFirst = (int)(ticks & 0xFFFFFF00); *pNext = (short)ticks; } return new Guid( bytes ); }


Siempre puede llamar a UuidCreateSequential; este es el "viejo" generador de guid (antes de 2000 cuando MSFT lo cambió a las guías de estilo más aleatorias a las que estamos acostumbrados hoy). Cambiaron el nombre de la antigua UuidCreate a UuidCreateSequential, y pusieron su nuevo generador de guid en una nueva implementación de UuidCreate. UuidCreateSequential es también lo que SQL Server usa en NewSequentialID (), y es tan único como las guías normales, pero con la ventaja de que son secuenciales si crea una pila de ellas seguidas en el mismo proceso.

using System; using System.Runtime.InteropServices; namespace System { public static class GuidEx { [DllImport("rpcrt4.dll", SetLastError = true)] private static extern int UuidCreateSequential(out Guid guid); private const int RPC_S_OK = 0; /// <summary> /// Generate a new sequential GUID. If UuidCreateSequential fails, it will fall back on standard random guids. /// </summary> /// <returns>A GUID</returns> public static Guid NewSeqGuid() { Guid sequentialGuid; int hResult = UuidCreateSequential(out sequentialGuid); if (hResult == RPC_S_OK) { return sequentialGuid; } else { //couldn''t create sequential guid, fall back on random guid return Guid.NewGuid(); } } } }


Usamos un método similar al que Doug publicó anteriormente en el modelo de Entity Framework, por lo que debe poder usar también Linq to SQL.

Mientras hacíamos esto, necesitábamos un generador de peine guía para probar, y terminamos construyendo esta pequeña herramienta para generar guías de peine en línea.

http://www.webdesigncompany.co.uk/comb-guid/

Espero que te ayude también.


C # (seguro) código (Complementos del NHibernate Guid Comb Generator)

Guid GenerateComb() { byte[] destinationArray = Guid.NewGuid().ToByteArray(); DateTime time = new DateTime(0x76c, 1, 1); DateTime now = DateTime.Now; TimeSpan span = new TimeSpan(now.Ticks - time.Ticks); TimeSpan timeOfDay = now.TimeOfDay; byte[] bytes = BitConverter.GetBytes(span.Days); byte[] array = BitConverter.GetBytes((long) (timeOfDay.TotalMilliseconds / 3.333333)); Array.Reverse(bytes); Array.Reverse(array); Array.Copy(bytes, bytes.Length - 2, destinationArray, destinationArray.Length - 6, 2); Array.Copy(array, array.Length - 4, destinationArray, destinationArray.Length - 4, 4); return new Guid(destinationArray); }

Un enlace a la fuente en github: https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Id/GuidCombGenerator.cs


@arul, @Doug

¿Por qué colocaste la parte de tiempo al final del GUID?

Pensé que los bytes iniciales son más importantes para ordenar, y ordenar es por qué la parte de tiempo se introdujo en primer lugar para evitar la fragmentación del índice.

Bien, encontré la respuesta , y esta respuesta de Bernhard Kircher y el sitio Comparing GUID y uniqueidentifier Values ​​(ADO.NET) a los que hace referencia.

Los GUID generados de esta manera, por lo tanto, no funcionarían de la misma manera en otras bases de datos que MS SQL-Server, pero esto no está relacionado con LINQ-to-SQL.

Perdón por las URL deformadas pero no tengo la reputación suficiente para publicar más enlaces.