简体   繁体   English

将 sql server rowversion 转换为 long 或 ulong?

[英]converting sql server rowversion to long or ulong?

What is the proper type for the rowversion (timestamp) data type? rowversion(时间戳)数据类型的正确类型是什么?

I know it is 8 bytes but i cannot find a link in MSDN which tell if it is a signed or unsigned long.我知道它是 8 个字节,但我在 MSDN 中找不到一个链接,它告诉它是有符号长还是无符号长。

which code should I use, does it even matter?我应该使用哪个代码,这有关系吗?

byte[] SqlTimeStamp;

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

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

It does matter.这很重要。 You want your comparison to have the same result as SQL Server's comparison.您希望您的比较结果与 SQL Server 的比较结果相同。 SQL Server uses unsigned comparisons on binary types: SQL Server 对二进制类型使用无符号比较:

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

If you do the same thing with long which is signed, 0xFFFFFFFFFFFFFFFF represents -1 .如果您对已签名的long执行相同的操作,则0xFFFFFFFFFFFFFFFF代表-1 That means your comparison will be incorrect;这意味着您的比较将不正确; it won't match with the same comparison done in SQL Server.它与在 SQL Server 中进行的相同比较不匹配。

What you definitely want is to use ulong where 0xFFFFFFFFFFFFFFFF is ulong.MaxValue .您绝对想要的是使用ulong ,其中0xFFFFFFFFFFFFFFFFulong.MaxValue

Endianness is also important字节序也很重要

Additionally, as Mark pointed out, BitConverter.GetUInt64 is not converting properly.此外,正如 Mark 指出的那样, BitConverter.GetUInt64没有正确转换。 Mark is not completely right - BitConverter is either big-endian or little-endian depending on the system it's running on.马克并不完全正确- BitConverter是大端或小端,具体取决于它运行的系统。 You can see this for yourself .你可以自己看看这个 Also, even if BitConverter was always little-endian, Array.Reverse is less performant with a heap allocation and byte-by-byte copying.此外,即使 BitConverter 始终是 little-endian, Array.Reverse在堆分配和逐字节复制方面的性能也较差。 BitConverter is just not semantically or practically the right tool for the job. BitConverter只是在语义上或实际上不是适合这项工作的工具。

This is what you want:这就是你想要的:

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

The cleanest solution最干净的解决方案

Update : If you use .NET Core 2.1 or later (or .NET Standard 2.1), you can use BinaryPrimitives.ReadUInt64BigEndian which is a perfect fit.更新:如果您使用 .NET Core 2.1 或更高版本(或 .NET Standard 2.1),您可以使用BinaryPrimitives.ReadUInt64BigEndian ,这是一个完美的选择。

On .NET Framework, here is the solution I use: Timestamp.cs .在 .NET Framework 上,这是我使用的解决方案: Timestamp.cs Basically once you cast to Timestamp , you can't go wrong.基本上,一旦你投到Timestamp ,你就不会出错。

Short answer: it doesn't matter but I'd choose UInt64 .简短的回答:没关系,但我会选择UInt64

Details: semantically it's equivalent to binary(8) so, strictly speaking, it's neither UInt64 nor Int64 but just a chunk of bytes (and in that way it should be managed).详细信息:从语义上讲,它等同于binary(8) ,所以严格来说,它既不是UInt64也不是Int64 ,而只是一块字节(并且应该以这种方式对其进行管理)。 That said I'd choose UInt64 because it's an incrementing number to hold row version then (from a logic point of view) 0xFFFFFFFFFFFFFFFF should be greater than 0 and it's not true for Int64 (because 64 bits set to 1 give -1 and it's less than 0 ).那就是说我会选择UInt64因为它是一个递增的数字来保存行版本(从逻辑的角度来看) 0xFFFFFFFFFFFFFFFF应该大于0而对于Int64则不是这样(因为 64 位设置为 1 给出-1并且它更少大于0 )。

Edit : note that, for reasons known only in the innest SQL Server designers circle, ROWVERSION is big-endian (while - obviously - bigint is not) then you first need to reverse bytes, see this answer for a nice implementation .编辑:请注意,由于仅在内部 SQL Server 设计人员圈子中已知的原因, ROWVERSION是大端(而 - 显然 - bigint不是)然后您首先需要反转字节,请参阅此答案以获得一个很好的实现

Neither will work correctly for purposes of comparing timestamp/rowversion values, if you're running on an x86 family CPU, because of endian.如果您在 x86 系列 CPU 上运行,由于 endian,两者都无法正常工作以比较时间戳/行版本值。 The first byte of a timestamp is most significant, but not so for little endian integer types.时间戳的第一个字节是最重要的,但对于小端整数类型而言并非如此。

Call Array.Reverse(ts) before calling BitConverter.ToUInt64(ts), and for the other direction, after calling BitConverter.GetBytes(tsUInt64)在调用 BitConverter.ToUInt64(ts) 之前调用 Array.Reverse(ts),而对于另一个方向,在调用 BitConverter.GetBytes(tsUInt64) 之后

I use this (updated):我用这个(更新):

private UInt64 GetUInt64ForRowVersion(byte[] rowVersion)
{
    byte[] rr = (byte[])rowVersion.Clone();
    if (BitConverter.IsLittleEndian) { Array.Reverse(rr); }
    return BitConverter.ToUInt64(rr, 0);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM