我正在使用SQL Server或Azure SQL数据库(取决于环境)。
在数据库内部我有一些使用数据类型timestamp
进行版本控制的表,其中一些表没有使用它。
例如:表格A
和B
列timestamp ver
,而表格C
和D
没有此列。
我正在使用Entity Framework。我能以某种方式安全地将此值(与byte[]
匹配)转换为uint64
吗?是否保证在转换较高值后,后一行被修改:如果我从表a
中获取行A
并从表b
B
中获取行a.convertedVer > b.convertedVer
} {且仅当a
被修改的时间晚于b
?
我需要处理请求:“给我A
匹配的所有行,并ver
高于myVer
”。
答案 0 :(得分:1)
是否保证在转换较高值后,后一行被修改了?
是的,来自MSDN:
rowversion数据类型只是一个递增数字(...)每个数据库都有一个递增的计数器,用于对a执行的每个插入或更新操作包含数据库中的rowversion列的表。
(我的重点)
顺便说一下,请注意{@ 1}}已弃用。目前,它只是timestamp
的同义词。
我可以以某种方式安全地将此值(与byte []匹配)转换为uint64吗?
是的,但某种程度这个词很讨厌。非常讨厌。
在T-SQL中,您可以编写类似
的查询rowversion
如您所知,实体框架将SELECT * FROM MyTable WHERE rowversion > @someRowversion
作为rowversion
返回。字节数组无法比较(没有自定义比较器)。所以我们不能写:
byte[8]
它无法编译。如果只有EF可以绕过C#编译器并将表达式转换为SQL呢! (当然它永远不会)。
现在是什么?
假设您有一个将db.MyTable.Where(t => t.RowVersion > someByteArray);
转换为byte[]
的转换器。 (这个转换器可以使用UInt64
,但是我现在还没有进行一些字节序细节。你不能写
BitConverter
EF会反对它无法将db.MyTable.Where(t => MyConverter.Convert(t.RowVersion) > someUInt64);
转换为SQL。和
MyConverter.Convert(t.RowVersion)
不是一个选项,因为它会将所有db.MyTable.AsEnumerable()
.Where(t => MyConverter.Convert(t.RowVersion) > someUInt64);
拉入内存。
也许我错过了一些非常明显的东西(我希望),但在EF LINQ查询中比较MyTable
值似乎是一个死胡同。我认为您最好使用存储过程或视图来实现您想要的目标。
修改强>
是的!幸运的是,我错过了一些东西,但并不太明显。正如Ari所解释的那样,可以创建一个方法存根 rowversion
,EF在将表达式转换为SQL时将其选中。它永远不会在CLR中执行。
提供更多背景资料:在EF资源中,它全部在Compare
。方法LinqExpressionNormalizer
查找许多方法名称,如果在表达式中找到,则将其转换为表达式并与包含表达式合并。这些方法是
VisitMethodCall()
Object.Equals(x, y)
x = y
Class.Compare(x, y)
x.Equals(y)
x.CompareTo(y)
答案 1 :(得分:1)
根据Gert Arnold的回答,保证较高的值是后一行被修改。
创建将byte[8]
转换为uint64
的代码并不难。我们可以使用BitConverter
或者我们可以简单地添加移位0,8,16,24,32 ......的字节。
最后一个问题:如何在Where RowVersion > someUInt64
中创建查询Entity Framework
。
很少有事实:
Where RowVersion > someUInt64
和Where RowVersion > someBytes
。Where RowVersion > someUInt64
和Where RowVersion > someBytes
。byte[]
和byte[]
以及byte[]
和uint64
进行比较。因此,即使数据库能够处理这些请求,我们也无法在C# Entity Framework
中创建此类请求。
我们需要C#
了解比较byte[]
和byte[]
或byte[]
和uint64
。第一种情况更容易。我们可以轻松地创建比较byte[]
和byte[]
的方法。
public static int Compare(this byte[] b1, byte[] b2)
{
throw new NotImplementedException();
}
我们不需要实现它。 T-SQL
已经实施了它。我们需要做的就是让C#
编译我们使用Compare
方法的代码。
现在我们可以将查询转换为:Where(v => v.Compare(someBytes) > 0)
。