[英]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
,其中0xFFFFFFFFFFFFFFFF
是ulong.MaxValue
。
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];
}
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.