17

rowversion(时间戳)数据类型的正确类型是什么?

我知道它是 8 个字节,但我在 MSDN 中找不到一个链接,它告诉它是有符号长还是无符号长。

我应该使用哪个代码,这有关系吗?

byte[] SqlTimeStamp;

long longConversion;
longConversion = BitConverter.ToInt64(SqlTimeStamp,0);
TimeStamp = BitConverter.GetBytes(longConversion);

ulong ulongConversion;
ulongConversion = BitConverter.ToUInt64(SqlTimeStamp,0);
TimeStamp = BitConverter.GetBytes(ulongConversion);
4

4 回答 4

27

这很重要。您希望您的比较结果与 SQL Server 的比较结果相同。SQL Server 对二进制类型使用无符号比较:

select case when 0x0FFFFFFFFFFFFFFF < 0xFFFFFFFFFFFFFFFF then 'unsigned' else 'signed' end

如果你用long签名做同样的事情,0xFFFFFFFFFFFFFFFF代表-1. 这意味着您的比较将不正确;它与在 SQL Server 中进行的相同比较不匹配。

您绝对想要的是使用ulongwhere 0xFFFFFFFFFFFFFFFFis ulong.MaxValue

字节序也很重要

此外,正如马克指出的那样,BitConverter.GetUInt64没有正确转换。马克并不完全正确-BitConverter是大端还是小端取决于它运行的系统。你可以自己看看这个。此外,即使 BitConverter 始终是 little-endian,Array.Reverse在堆分配和逐字节复制方面的性能也较差。BitConverter只是在语义上或实际上不是工作的正确工具。

这就是你想要的:

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];
}

最干净的解决方案

更新:如果您使用 .NET Core 2.1 或更高版本(或 .NET Standard 2.1),您可以使用BinaryPrimitives.ReadUInt64BigEndian非常合适的版本。

在 .NET Framework 上,这是我使用的解决方案:Timestamp.cs。基本上,一旦你投到Timestamp,你就不会出错。

于 2016-07-01T16:18:02.700 回答
9

如果您在 x86 系列 CPU 上运行,由于 endian,两者都无法正常工作以比较时间戳/行版本值。时间戳的第一个字节是最重要的,但对于小端整数类型而言并非如此。

在调用 BitConverter.ToUInt64(ts) 之前调用 Array.Reverse(ts),而对于另一个方向,在调用 BitConverter.GetBytes(tsUInt64) 之后

于 2014-04-30T22:58:18.457 回答
9

简短的回答:没关系,但我会选择UInt64.

细节:从语义上讲,它等同于binary(8)so,严格来说,它既不是UInt64也不是Int64,只是一块字节(并且应该以这种方式对其进行管理)。那就是说我会选择UInt64,因为它是一个递增的数字来保存行版本,然后(从逻辑的角度来看)0xFFFFFFFFFFFFFFFF应该大于0并且它不是真的Int64(因为 64 位设置为 1 给出-1并且它小于0)。

编辑:请注意,由于仅在内部 SQL Server 设计人员圈子中已知的原因,ROWVERSION是大端(而 - 显然 -bigint不是)然后你首先需要反转字节,请参阅这个答案以获得一个很好的实现

于 2014-01-15T19:08:14.677 回答
1

我用这个(更新):

private UInt64 GetUInt64ForRowVersion(byte[] rowVersion)
{
    byte[] rr = (byte[])rowVersion.Clone();
    if (BitConverter.IsLittleEndian) { Array.Reverse(rr); }
    return BitConverter.ToUInt64(rr, 0);
}
于 2018-01-11T05:59:27.510 回答