Insert und Update Timestamp für MS Sync Framework
Wer sich schon mal mit dem Microsoft Sync Framework für .NET beschäftigt hat, weiß das man für eine Batch Synchronisation in den Tabellen mindestens zwei Timestamp-Felder benötigt; eins für Insert und eins für Update.
Natürlich kann man in einer Tabelle nicht 2 oder mehr Felder mit Typ Timestamp anlegen; macht ja auch keinen Sinn, da bei jedem Update alle Felder auf das gleiche aktuelle Timestamp gesetzt werden würde.
Im MS SQL Server ist das mit einem einfachen Kniff leicht möglich, ohne eine Programmanpassung vornehmen zu müssen. Für Update legt man ein Feld mit Typ Timestamp an, für Insert ein Feld vom Typ Binary(8), bei dem das Default auf @@DBTS +1 gesetzt wird. Natürlich weist man dem Feld nie ein Wert zu, sondern belässt man den Default; also dem Timestamp zu Zeitpunkt des Inserts.
Sieht dann so aus:
USE tempdb
--TempDB um mit @@DBTS die richtigen Werte zu bekommen
GO
CREATE TABLE #TS
(Id int identity(1,1),
UpdateTS timestamp,
InsertTS binary(6) DEFAULT @@DBTS + 1);
-- 3 Datensätze zur Demo
INSERT INTO #TS DEFAULT VALUES;
INSERT INTO #TS DEFAULT VALUES;
INSERT INTO #TS DEFAULT VALUES;
-- Einen davon Updaten
UPDATE #TS
SET InsertTS = InsertTS
WHERE Id = 3
-- Wie sieht es aus?
SELECT * FROM #TS;
-- ... gut
GO
DROP TABLE #TS
Ergebnis:
Id UpdateTS InsertTS
----------- ------------------ --------------
1 0x000000000000401C 0x00000000401C
2 0x000000000000401D 0x00000000401D
3 0x000000000000401F 0x00000000401E
Wie erwartet und gewünscht.
Nun möchte ich das Ganze mit einer MS SQL Server Compact Editon 3.5 SP1 Datenbank nutzen.
Wenn man zur Tabellen-Anlage das SQL Server Management Studio nutzt, fällt einen zunächst mal auf, das im SQL Server CE der Datentyp nun RowVersion statt Timestamp heißt; sehr positiv, wie ich finde, den Timestamp ist irreführend, das es nichts mit Datum – Uhrzeit zu tun hat; es ist nur eine fortlaufende Nummer und RowVersion ist die wesentlich passendere Bezeichnung; bleibt zu Hoffen, dass die Bezeichnung dann demnächst auch im SQL Server Einzug hält; vielleicht schon mit SQL Server 2008 R2? Beim CREATE TABLE kann man sowohl Timestamp als auch RowVersion verwenden; ich verwende mal zu Demo-Zwecken letzteres.
Hier also das Script für SQL Server CE 3.5; man muss aber jeden Befehl einzeln im SSMS ausführen, da keine Batches unterstütz werden. Das bei @@DBTS das + 1 fehlt, liegt daran, das beim ersten Test ein falscher (um eins zu hoher) Wert raus kam … aber das kommt noch.
-- Bei CE jeden Schritt einzeln abarbeiten!!
CREATE TABLE TS
(Id int identity(1,1),
UpdateTS rowversion,
InsertTS binary(8) DEFAULT @@DBTS);
-- 3mal einzeln ausführen, bitte!
INSERT INTO TS (UpdateTS) VALUES(NULL);
-- Einen davon Updaten
UPDATE TS
SET InsertTS = InsertTS
WHERE Id = 3
SELECT * FROM TS;
GO
DROP TABLE TS
Ergebnis:
Id UpdateTS InsertTS
----------- ------------------ ------------------
1 0x000000000000003F 0x000000000000003F
2 0x0000000000000040 0x000000000000003F
3 0x0000000000000042 0x000000000000003F
Ähem, ja; es funktioniert … fast so irgendwie. Es hat den Anschein, dass zum Zeitpunkt der Tabellenanlage die Funktion @@DBTS aufgelöst und danach nur noch dieser Wert verwendet wird, nicht der aktuelle. Das ist natürlich suboptimal. Hilft also alles nichts, man muss sein Insert-Statement anpassen in der Form:
INSERT INTO TS (InsertTS) VALUES(@@DBTS + 1);
Hier also doch wieder @@DBTS + 1.
Ergebnis:
Id UpdateTS InsertTS
----------- ------------------ ------------------
1 0x000000000000003F 0x000000000000003F
2 0x0000000000000040 0x000000000000003F
3 0x0000000000000042 0x000000000000003F
4 0x0000000000000043 0x0000000000000043
5 0x0000000000000044 0x0000000000000044
Was sagt uns das? Immer alles ausgiebig testen, auch wenn es zunächst augenscheinlich funktioniert.