比较一个数据库中的时间戳值

时间:2014-02-12 15:23:32

标签: sql sql-server entity-framework azure-sql-database

我正在使用SQL Server或Azure SQL数据库(取决于环境)。

在数据库内部我有一些使用数据类型timestamp进行版本控制的表,其中一些表没有使用它。

例如:表格ABtimestamp ver,而表格CD没有此列。

我正在使用Entity Framework。我能以某种方式安全地将此值(与byte[]匹配)转换为uint64吗?是否保证在转换较高值后,后一行被修改:如果我从表a中获取行A并从表b B中获取行a.convertedVer > b.convertedVer } {且仅当a被修改的时间晚于b

我需要处理请求:“给我A匹配的所有行,并ver高于myVer”。

2 个答案:

答案 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()
  • CompareString(VB):Object.Equals(x, y)
  • 比较(静态):x = y
  • 等于(实例):Class.Compare(x, y)
  • CompareTo(实例):x.Equals(y)
  • 包含(实例):x.CompareTo(y)

答案 1 :(得分:1)

根据Gert Arnold的回答,保证较高的值是后一行被修改。

创建将byte[8]转换为uint64的代码并不难。我们可以使用BitConverter或者我们可以简单地添加移位0,8,16,24,32 ......的字节。

最后一个问题:如何在Where RowVersion > someUInt64中创建查询Entity Framework

很少有事实:

  1. MS SQL理解Where RowVersion > someUInt64Where RowVersion > someBytes
  2. Azure SQL了解Where RowVersion > someUInt64Where RowVersion > someBytes
  3. C#无法与byte[]byte[]以及byte[]uint64进行比较。
  4. 因此,即使数据库能够处理这些请求,我们也无法在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)