Como observado por Alberto Ferrari e discutido aqui no StackOverflow , o Microsoft SQL Server classifica os GUIDs comparando os bytes em uma ordem específica. Como o MySQL classificará um
BINARY(16)
"direto", tudo o que precisamos fazer é reordenar os bytes ao ler/gravar no banco de dados. NHibernate nos permite definir tipos de dados personalizados, que podem ser usados em mapeamentos entre banco de dados e objetos. Eu implementei um
BinaryGuidType
, capaz de reordenar os bytes produzidos pelo Guid.ToByteArray()
de acordo com a maneira como o MSSQL classifica os GUIDs e os reordena de volta para o formato aceito pelo Guid(byte[])
construtor. A ordem dos bytes fica assim:
int[] ByteOrder = new[] { 10,11,12,13,14,15,8,9,6,7,4,5,0,1,2,3 };
Salvando um
System.Guid
para um BINARY(16)
fica assim:var bytes = ((Guid) value).ToByteArray();
var reorderedBytes = new byte[16];
for (var i = 0; i < 16; i++)
{
reorderedBytes[i] = bytes[ByteOrder[i]];
}
NHibernateUtil.Binary.NullSafeSet(cmd, reorderedBytes, index);
Lendo os bytes de volta para um
System.Guid
fica assim:var bytes = (byte[]) NHibernateUtil.Binary.NullSafeGet(rs, names[0]);
if (bytes == null || bytes.Length == 0) return null;
var reorderedBytes = new byte[16];
for (var i = 0 ; i < 16; i++)
{
reorderedBytes[ByteOrder[i]] = bytes[i];
}
Código-fonte completo para o
BinaryGuidType
aqui.
Isso parece funcionar bem. Criando e persistindo 10.000 novos objetos em uma tabela, eles são armazenados de forma totalmente sequencial, sem sinais de fragmentação do índice.