Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

convertendo o sql server rowversion para long ou ulong?


Isso importa. Você deseja que sua comparação tenha o mesmo resultado da comparação do SQL Server. O SQL Server usa comparações não assinadas em tipos binários:
select case when 0x0FFFFFFFFFFFFFFF < 0xFFFFFFFFFFFFFFFF then 'unsigned' else 'signed' end

Se você fizer a mesma coisa com long que é assinado, 0xFFFFFFFFFFFFFFFF representa -1 . Isso significa que sua comparação estará incorreta; não corresponderá à mesma comparação feita no SQL Server.

O que você definitivamente quer é usar ulong onde 0xFFFFFFFFFFFFFFFF é ulong.MaxValue .

O endianness também é importante


Além disso, como Mark apontou, BitConverter.GetUInt64 não está convertendo corretamente. Mark não está totalmente certo - BitConverter é big-endian ou little-endian dependendo do sistema em que está sendo executado. Você pode ver você mesmo . Além disso, mesmo que o BitConverter sempre fosse little-endian, Array.Reverse é menos eficiente com uma alocação de heap e cópia byte a byte. BitConverter não é semanticamente ou praticamente a ferramenta certa para o trabalho.

Isso é o que você quer:
static ulong BigEndianToUInt64(byte[] bigEndianBinary)
{
    return ((ulong)bigEndianBinary[0] << 56) |
           ((ulong)bigEndianBinary[1] << 48) |
           ((ulong)bigEndianBinary[2] << 40) |
           ((ulong)bigEndianBinary[3] << 32) |
           ((ulong)bigEndianBinary[4] << 24) |
           ((ulong)bigEndianBinary[5] << 16) |
           ((ulong)bigEndianBinary[6] <<  8) |
                   bigEndianBinary[7];
}

A solução mais limpa


Atualizar :Se você usa o .NET Core 2.1 ou posterior (ou .NET Standard 2.1), pode usar BinaryPrimitives.ReadUInt64BigEndian que é um ajuste perfeito.

No .NET Framework, aqui está a solução que uso:Timestamp.cs . Basicamente, depois de transmitir para Timestamp , você não pode errar.