2014-02-12 18 views
0

我正在使用SQL Server或Azure SQL數據庫(取決於環境)。比較一個數據庫中的時間戳值

內部數據庫我有一些表使用數據類型timestamp進行版本控制,其中一些不使用它。

例如:表AB具有柱timestamp ver和表CD不具有這種柱。

我正在使用實體框架。我能以某種方式安全地將此值(匹配到byte[])轉換爲uint64?是否保證轉換後的較高值是後面的行被修改:如果我從表A中的行a和表中的表B中的行a.convertedVer > b.convertedVer當且僅當a被修改爲晚於b

我需要處理請求:「給我所有與A匹配的行,並且ver高於myVer」。

+0

'byte []'有什麼問題?您不必檢查值是否更高,只要它相等即可。無論如何,是的,時間戳將始終是一個8字節的值,所以'UInt64'應該沒問題。 – Luaan

+0

我更新了問題。我需要處理請求:給我所有來自匹配的行,並具有比myVer更高的行。 – Ari

回答

1

據格特阿諾德回答可以保證較高值後連續被修改。

創建代碼轉換byte[8]uint64並不難。我們可以使用BitConverter或者我們可以簡單地添加移位了0,8,16,24,32,...的數據。

最後一個問題:如何在Entity Framework中創建查詢Where RowVersion > someUInt64

幾個事實:

  1. MS SQL理解Where RowVersion > someUInt64Where RowVersion > someBytes
  2. Azure SQL瞭解Where RowVersion > someUInt64Where RowVersion > someBytes
  3. C#無法比較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)

+0

不錯!我爲自己的回答添加了一些背景。您可以將您的答案標記爲已接受,以引導未來的讀者參與解決方案。 –

1

是否保證轉換後的值越高後面的行被修改?

是的,從MSDN

的rowversion數據類型僅僅是一個遞增數(...)每個數據庫具有一計數器,該計數器是遞增每個插入或更新操作即在包含數據庫內的rowversion列的表上執行。

(我的重點)

順便說一句,注意timestamp已被棄用。目前,它只是rowversion的同義詞。

可以以某種方式安全地將此值(匹配字節[])轉換爲uint64嗎?

是的,但字莫名其妙地是討厭的。非常討厭。

在T-SQL當你知道你可以編寫

SELECT * FROM MyTable WHERE rowversion > @someRowversion 

查詢,實體框架返回rowversionbyte[8]。字節數組不具有可比性(沒有自定義比較器)。因此,我們不能寫:

db.MyTable.Where(t => t.RowVersion > someByteArray); 

它不編譯。如果只有EF可以繞過C#編譯器並將表達式轉換爲SQL! (當然它永遠不會)。

現在怎麼辦?

比方說,你已經得到了byte[]轉換成UInt64的轉換器。 (這個轉換器可以使用一個BitConverter,但是我現在沒有涉及一些字節順序的細節)。你不能寫

db.MyTable.Where(t => MyConverter.Convert(t.RowVersion) > someUInt64); 

EF會反對它不能將MyConverter.Convert(t.RowVersion)翻譯成SQL。並且

db.MyTable.AsEnumerable() 
      .Where(t => MyConverter.Convert(t.RowVersion) > someUInt64); 

不是一個選項,因爲它會將所有MyTable拉入內存。

也許我失去了一些東西很明顯(我希望),但在EF LINQ查詢比較rowversion值似乎是一個死衚衕。我認爲你最好使用存儲過程或視圖來實現你想要的。

編輯

所以,是的!幸運的是,我錯過了一些東西,但不是太明顯。正如阿里解釋,有可能創造一個方法存根Compare該EF拾取在翻譯的表達到SQL。它從來沒有在CLR中執行過。

爲了讓更多的背景:在EF源這一切都在LinqExpressionNormalizer。方法VisitMethodCall()查找若干方法名稱,如果在表達式中找到該方法名稱,它們將轉換爲表達式並與包含的表達式合併。這些方法

  • 的equals(靜態):Object.Equals(x, y)
  • CompareString(VB):x = y
  • 比較(靜態):Class.Compare(x, y)
  • 的equals(實例):x.Equals(y)
  • 的CompareTo(實例): x.CompareTo(y)
  • 包含(實例):List<T> x.Contains(y)
+0

我發現如果我爲'byte []''''定義'Compare'方法做任何事情(例如拋出'NotImplementedException'),我可以寫'.Where(t => t.RowVersion.Compare(myVer)> 0)' 。這非常醜陋,但按預期工作。我認爲MS應該將'rowversion'實現爲'uint64'。 – Ari

+0

好吧,這很酷!你介意給出一個簡單的解釋這種方法作爲你自己的問題的答案嗎? –

+0

我解釋了它。 – Ari