Jako obserwowany przez Alberto Ferrari
i omówiono tutaj na StackOverflow
, Microsoft SQL Server sortuje identyfikatory GUID, porównując bajty w określonej kolejności. Ponieważ MySQL posortuje BINARY(16)
„prosto do przodu”, wszystko, co musimy zrobić, to zmienić kolejność bajtów podczas odczytu/zapisu do bazy danych.
NHibernate pozwala nam zdefiniować niestandardowe typy danych, które mogą być używane w mapowaniach między bazą danych a obiektami. Zaimplementowałem BinaryGuidType
, z możliwością zmiany kolejności bajtów utworzonych przez Guid.ToByteArray()
zgodnie ze sposobem, w jaki MSSQL sortuje identyfikatory GUID i zmienia ich kolejność z powrotem do formatu akceptowanego przez Guid(byte[])
konstruktor.
Kolejność bajtów wygląda tak:
int[] ByteOrder = new[] { 10,11,12,13,14,15,8,9,6,7,4,5,0,1,2,3 };
Zapisywanie System.Guid
do BINARY(16)
idzie tak:
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);
Odczytywanie bajtów z powrotem do System.Guid
idzie tak:
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];
}
Pełny kod źródłowy BinaryGuidType
tutaj.
Wydaje się, że to działa dobrze. Tworząc i utrzymując 10 000 nowych obiektów w tabeli, są one przechowywane całkowicie sekwencyjnie, bez oznak fragmentacji indeksu.