rowVersion 在 Entityframe 工作中映射到字节 [8],但手动转换时它是字节 [18]

问题描述 投票:0回答:3

我从数据库中获取

rowVersion
作为
byte[8]

var rowVersion= new MyContext().Employee.FirstOrDefault(x => x.Id).rowVersion;
// suppose above the actual databse values is 0x0000000000038B8C
var rowVersionToLong = BitConverter.ToInt64(rowVersion,0);

现在如果我手动执行此操作:

String rowversionStr = "0x0000000000038B8C";
byte[] mybyteArray = System.Text.ASCIIEncoding.ASCII.GetBytes(rowversionStr);

这给了我

byte[18]
,当我将其转换为
Int64
时,它给了我不同的价值。

我不明白。

我想将

rowVersion
作为参数传递给
WebApi
get 方法。由于
Byte[]
是不允许的,所以我将它作为字符串传递

更新:

 public IHttpActionResult Get(string rowVersion, int id)
    {

        var exisitingRowVersion = long.Parse(rowVersion.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);

        var result = new MyContext().employees.ToList().Where(x => x.Id == 2 && BitConverter.ToInt64(x.RowVersion, 0) > exisitingRowVersion);

        return Ok(result);

不明白为什么这个不起作用。我们基本上是在比较长与长

c#-4.0 entity-framework-6 rowversion
3个回答
5
投票

您面临三个主要问题。本来不应该这么复杂,但事实就是如此。

这是我使用的解决方案:Timestamp.cs。这更容易。我会在最后举一个例子。

1.不比较苹果与苹果

rowVersion
是一个 8 字节数组。每个字节代表 64 位整数的一部分,范围为 0 - 255。

System.Text.ASCIIEncoding.ASCII.GetBytes
编码 ASCII 字符串,而不是整数。它返回一个 18 字节数组。每个字节代表“一个文本字符”,并且为“0”(48) -“9”(57)、“A”(65) -“F”(70) 或“x”(120)。 解决方案:您的方向是正确的

long.Parse("0x0000000000038B8C".Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);


2. SQL Server 时间戳以大端存储

BitConverter.ToUInt64

是大尾数还是小尾数,具体取决于您运行的系统上

ulong
是大尾数还是小尾数。您可以
亲自看看这个
。无论您在什么系统上运行,您都需要一个始终为大尾数的转换: 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]; }

3.二进制比较是无符号的

当 SQL Server 比较

0x0FFFFFFFFFFFFFFF < 0xFFFFFFFFFFFFFFFF

时,

0xFFFFFFFFFFFFFFFF
更大。为了保持 SQL Server 处理它的相同含义,您必须使用
ulong
 而不是 
long
。否则,
0xFFFFFFFFFFFFFFFF
会变成
-1L
,而不是 SQL Server 所认为的
ulong.MaxValue

当然,在使用

timestamp

列的高位之前必须发生 9 万亿次事情,但是您可以使用相同的代码来比较以其他方式生成的两个

binary(8)
时间戳。重要的是复制 SQL Server 的比较行为。

最干净的解决方案

这是我使用的解决方案:

Timestamp.cs

您的代码变为:

var existingRowVersion = (Timestamp)ulong.Parse(rowVersion.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var result = new MyContext().employees.ToList().Where(x => x.Id == 2 && (Timestamp)x.RowVersion > exisitingRowVersion);

基本上一旦你投射到
Timestamp

,你就不会出错。


遗憾的是,无论您使用哪种方法,都没有好的方法可以在服务器端而不是客户端应用此过滤器。这就是

这个问题的主题。猜猜我发现了什么! 使用 Entity Framework 6.1.3 实现此目的的方法!那有多酷?

但是

,这与您的问题无关,您绝对应该将 Id == 2 过滤器放在服务器端(在调用 ToList 之前)。否则,您会将整个表传输到应用程序,然后在客户端丢弃除一行之外的所有内容。你应该这样做:


var existingRowVersion = (Timestamp)ulong.Parse(rowVersion.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var result = new MyContext().employees.Where(x => x.Id == 2).ToList().Where((Timestamp)x.RowVersion > exisitingRowVersion);

最佳:

var existingRowVersion = (Timestamp)ulong.Parse(rowVersion.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var employee = new MyContext().employees.SingleOrDefault(x => x.Id == 2); if (employee == null) ... // Deleted else if ((Timestamp)employee.RowVersion > exisitingRowVersion) ... // Updated



2
投票

对我来说,可以使用

Convert.FromBase64String

将“AAAxxx==”转换为字节数组,反之亦然。


长话短说:

在我的例子中,我从 SQL 2016 DB 获取复杂对象的输出,包括来自使用 FOR JSON PATH 的查询的 RowVersion 和

SQL 将字符串基数 64 中的 RowVersion 和日期转换为字符串

,并直接使用该输出作为结果,但何时在 MVCx 或 WCF 中用作请求有效负载会失败,因为它们与 rowversion 转换配合得很好,就像从对象序列化为 JSON 的输出(如 WCF 或 MVCx 那样):rowversion 作为字节数组,日期作为 /Date(###)。 为了将 JSON-SQL 的输出转换为兼容 JSON-MVC-WCF 的格式,我必须使用扩展在服务器中的输出之前转换响应,该扩展在本例中将 RowVersion 的示例值 AAAxxx== 转换为 [0 ,0,0,#,#,#] 并为此传递 AAAxxx== 作为 Convert.FromBase64String 的参数并迭代字节数组以输出预期结果。


0
投票
byte[8]

/

timestamp
rowversion
转换为相同的格式以进行比较。
例如。乐观并发检查你会看到这样的参数。

@p3='0x0000000005B7566B'

在深入研究 EF Core 的源代码但没有找到他们在哪里做之后,我最终发现了这个非常简单的方法:

Convert.ToHexString(order.RowVersion) // gives 8 bytes Convert.FromHexString("0000000005B7566B") // don't include the 0x

PS。我从来没有真正理解这些“AAAxxx==”时间戳。这对任何人来说都是一种有用的格式吗?

© www.soinside.com 2019 - 2024. All rights reserved.