Vorgehensweise: Verwenden eines benutzerdefinierten Systems zur Änderungsnachverfolgung
Für viele Anwendungen müssen die Änderungen in der Serverdatenbank nachverfolgt werden, sodass diese während einer späteren Synchronisierungssitzung an die Clients weitergegeben werden können. In diesem Thema werden die Voraussetzungen für ein System zur Änderungsnachverfolgung beschrieben und das Erstellen eines benutzerdefinierten Systems erläutert, das von Sync Framework verwendet werden kann. In einigen Fällen ist eine benutzerdefinierte Änderungsnachverfolgung geeignet. Dies bedeutet jedoch auch eine höhere Komplexität und kann sich auf die Leistung der Serverdatenbank auswirken. Wenn Sie SQL Server 2008 verwenden, wird die Änderungsnachverfolgungsfunktion von SQL Server empfohlen. Weitere Informationen dazu finden Sie unter Vorgehensweise: Verwenden der SQL Server-Änderungsnachverfolgung.
Servervoraussetzungen für Synchronisierungsszenarien
Bei der Entwicklung von Sync Framework wurde darauf geachtet, dass die Auswirkungen auf die Serverdatenbank möglichst gering bleiben. Deshalb richtet sich das Ausmaß etwaiger Änderungen an der Serverdatenbank zum Zweck der Änderungsnachverfolgung danach, welchen Funktionsumfang eine Anwendung haben soll. Bedenken Sie dabei Folgendes:
Die einfachste Variante besteht in der Bereitstellung einer nur zum Herunterladen gedachten Momentaufnahme der Daten ("Snapshot"). Dies erfordert keine Änderungen.
Am anderen Ende der Skala steht die bidirektionale Synchronisierung mit vollständiger Änderungsnachverfolgung und Konflikterkennung.
Die folgende Tabelle enthält eine Übersicht darüber, wie Sie Sync Framework verwenden können. Außerdem können Sie dieser Tabelle die Voraussetzungen entnehmen, die die Serverdatenbank jeweils erfüllen muss.
Szenario | Primärschlüssel oder eindeutige Spalte1 | Nachverfolgung der Aktualisierungszeit | Nachverfolgung der Einfügezeit | Nachverfolgung der Löschzeit | Nachverfolgung der Client-ID bei Aktualisierungen | Nachverfolgung der Client-ID bei Einfügungen | Nachverfolgung der Client-ID bei Löschungen |
---|---|---|---|---|---|---|---|
Herunterladen einer Momentaufnahme der Daten auf den Client |
nein |
nein |
nein |
nein |
nein |
nein |
nein |
Herunterladen inkrementeller Einfügungen und Aktualisierungen auf den Client |
ja |
ja |
ja2 |
nein |
nein |
nein |
nein |
Herunterladen inkrementeller Einfügungen, Aktualisierungen und Löschungen auf den Client |
ja |
ja |
ja2 |
ja |
nein |
nein |
nein |
Hochladen von Einfügungen auf den Server |
ja |
nein |
nein |
nein |
nein |
nein3 |
nein |
Hochladen von Einfügungen und Aktualisierungen auf den Server |
ja |
nein |
nein |
nein |
nein3 |
nein3 |
nein |
Hochladen von Einfügungen, Aktualisierungen und Löschungen auf den Server |
ja |
nein |
nein |
nein |
nein3 |
nein3 |
nein3 |
Bidirektionale Einfügungen und Aktualisierungen mit Konflikterkennung |
ja |
ja |
ja2 |
nein |
ja4 |
ja4 |
nein |
Bidirektionale Einfügungen, Aktualisierungen und Löschungen mit Konflikterkennung |
ja |
ja |
ja2 |
ja |
ja4 |
ja4 |
ja4 |
1 Die Primärschlüssel müssen für alle Knoten eindeutig sein und dürfen nicht wiederverwendet werden. Dies bedeutet, dass der Primärschlüssel einer Zeile nicht für eine andere Zeile verwendet werden darf, wenn diese Zeile gelöscht wird. Identitätsspalten sollten üblicherweise nicht für verteilte Umgebungen verwendet werden. Weitere Informationen zu Primärschlüsseln finden Sie unter Auswählen eines geeigneten Primärschlüssels für eine verteilte Umgebung.
2 Erforderlich, wenn zwischen Einfügungen und Aktualisierungen unterschieden werden soll. Weitere Informationen dazu finden Sie im Abschnitt "Ermitteln der auf einen Client herunterzuladenden Datenänderungen" weiter unten.
3 Erforderlich, wenn potenziell mehrere Clients eine Zeile ändern können und Sie herausfinden möchten, welcher Client die jeweilige Änderung vorgenommen hat. Weitere Informationen dazu finden Sie weiter unten in diesem Thema unter "Identifizieren des Clients, der eine Datenänderung vorgenommen hat".
4 Erforderlich, wenn von einem Client vorgenommene Änderungen nicht wieder als Echo an diesen Client zurückgegeben werden sollen. Weitere Informationen dazu finden Sie unter "Identifizieren des Clients, der eine Datenänderung vorgenommen hat" weiter unten.
Hinweis
Zusätzlich zu den weiter oben beschriebenen Änderungen werden Sie in den meisten Fällen auch gespeicherte Prozeduren für den Datenzugriff erstellen. Die meisten Beispiele in dieser Dokumentation verwenden Inline-SQL, weil dort einfacher darstellbar ist, was im Code passiert. In Produktionsanwendungen empfiehlt es sich, gespeicherte Prozeduren zu verwenden, weil sie Code kapseln, üblicherweise bessere Leistungswerte haben und, wenn sie richtig geschrieben sind, im Vergleich zu Inline-SQL mehr Sicherheit bieten.
Ermitteln der auf einen Client herunterzuladenden Datenänderungen
Sowohl bei der Nur-Download-Synchronisierung als auch bei der bidirektionalen Synchronisierung müssen Sie die Änderungen auf dem Server nachverfolgen, damit Sync Framework bestimmen kann, welche Änderungen auf die Clients heruntergeladen werden müssen. Auch wenn Sync Framework nicht spezifisch vorgibt, wie die Änderungsnachverfolgung zu unterstützen ist, gibt es eine allgemein übliche Herangehensweise, die im Folgenden näher beschrieben wird:
Fügen Sie jeder zu synchronisierenden Tabelle eine Spalte hinzu, die nachverfolgt, wann eine Zeile in die Serverdatenbank eingefügt wurde.
Fügen Sie eine Spalte und gegebenenfalls einen Trigger hinzu, um nachzuverfolgen, wann eine Zeile in der Serverdatenbank zum letzten Mal aktualisiert wurde.
Fügen Sie eine Tombstonetabelle und einen Trigger hinzu, um nachzuverfolgen, wann eine Zeile aus der Serverdatenbank gelöscht wurde. Wenn zwar keine Daten vom Server gelöscht werden sollen, aber Löschungen an den Client gesendet werden müssen, können logische Löschungen wie folgt in der Basistabelle nachverfolgt werden: Verwenden Sie eine Spalte, üblicherweise eine Spalte des Typs bit, um anzuzeigen, dass eine Zeile gelöscht wurde. Fügen Sie dann eine weitere Spalte hinzu, um den Zeitpunkt der Löschung nachzuverfolgen.
Diese Spalten und Tombstonetabellen werden zusammen mit Ankern verwendet, um zu ermitteln, welche Einfügungen, Aktualisierungen und Löschungen heruntergeladen werden müssen. Ein Anker ist nichts weiter als ein Zeitpunkt, der zum Definieren der zu synchronisierenden Änderungen verwendet wird. Betrachten wir dazu die folgenden Abfragen:
Die Abfrage, die Sie für die SelectIncrementalInsertsCommand-Eigenschaft festlegen. Diese Abfrage lädt inkrementelle Einfügungen aus der
Sales.Customer
-Tabelle in der Sync Framework-Beispieldatenbank herunter und geht dabei wie folgt vor:SELECT CustomerId, CustomerName, SalesPerson, CustomerType FROM Sales.Customer WHERE InsertTimestamp > @sync_last_received_anchor AND InsertTimestamp <= @sync_new_received_anchor
Weitere Informationen zu dieser und anderen Eigenschaften im Zusammenhang mit Synchronisierungsbefehlen finden Sie unter Vorgehensweise: Angeben der Synchronisierungsart (Momentaufnahmen-, Nur-Download-, Nur-Upload- oder bidirektionale Synchronisierung).
Die Abfrage, die Sie für die SelectNewAnchorCommand-Eigenschaft festlegen. Diese Abfrage ruft einen Zeitpunktwert ab. Die
InsertTimestamp
-Spalte speichert Timestampwerte. Deshalb verwendet die Abfrage die in SQL Server 2005 Service Pack 2 eingeführte Transact-SQL-MIN_ACTIVE_ROWVERSION
-Funktion, um wie folgt aus der Serverdatenbank einen Timestampwert abzurufen:SELECT @sync_new_received_anchor = MIN_ACTIVE_ROWVERSION - 1
MIN_ACTIVE_ROWVERSION gibt den niedrigsten aktiven timestamp-Wert (auch bekannt als rowversion-Wert) zurück, der in der aktuellen Datenbank vorhanden ist. Ein timestamp-Wert ist aktiv, wenn er in einer Transaktion verwendet wird, für die noch kein Commit ausgeführt wurde. Wenn keine aktiven Werte in der Datenbank vorhanden sind, gibt MIN_ACTIVE_ROWVERSION denselben Wert zurück wie @@DBTS + 1. MIN_ACTIVE_ROWVERSION erweist sich z. B. bei Datensynchronisierungen und anderen Szenarien als nützlich, in denen für die Gruppierung von Änderungen timestamp-Werte verwendet werden. Wenn eine Anwendung in ihren Ankerbefehlen statt MIN_ACTIVE_ROWVERSION @@DBTS verwendet, ist es möglich, dass Änderungen fehlen, die aktiv sind, wenn die Synchronisierung stattfindet.
Wenn die Sales.Customer
-Tabelle zum ersten Mal synchronisiert wird, passiert Folgendes:
Der neue Ankerbefehl wird ausgeführt. Der Befehl gibt den Wert
0x0000000000000D49
zurück. Dieser Wert wird in der Clientdatenbank gespeichert. Die Tabelle wurde bisher noch nicht synchronisiert. Deshalb gibt es keinen Ankerwert, der in der Clientdatenbank von einer vorherigen Synchronisierung gespeichert wurde. In diesem Fall verwendet Sync Framework den niedrigsten Wert, der für den SQL Server-Datentyp timestamp verfügbar ist:0x0000000000000000
. Daraufhin wird von Sync Framework die folgende Abfrage ausgeführt. Diese Abfrage lädt das Schema und alle Zeilen aus der Tabelle herunter.exec sp_executesql N'SELECT CustomerId, CustomerName, SalesPerson, CustomerType FROM Sales.Customer WHERE (InsertTimestamp > @sync_last_received_anchor AND InsertTimestamp <= @sync_new_received_anchor)',N'@sync_last_received_anchor timestamp, @sync_new_received_anchor timestamp', @sync_last_received_anchor=0x0000000000000000, @sync_new_received_anchor=0x0000000000000D49
Während der zweiten Synchronisierung wird der neue Ankerbefehl ausgeführt. Seit der letzten Synchronisierung wurden Zeilen eingefügt. Der Befehl gibt daher den Wert
0x0000000000000D4C
zurück. Die Tabelle wurde zuvor bereits synchronisiert. Daher kann Sync Framework den Ankerwert0x0000000000000D49
abrufen. Dieser Wert ist in der Clientdatenbank von der vorherigen Synchronisierung gespeichert. Daraufhin wird die folgende Abfrage ausgeführt. Die Abfrage lädt nur die Zeilen aus der Tabelle herunter, die zwischen den zwei Ankerwerten eingefügt wurden.exec sp_executesql N'SELECT CustomerId, CustomerName, SalesPerson, CustomerType FROM Sales.Customer WHERE (InsertTimestamp > @sync_last_received_anchor AND InsertTimestamp <= @sync_new_received_anchor)', N'@sync_last_received_anchor timestamp, @sync_new_received_anchor timestamp', @sync_last_received_anchor=0x0000000000000D49, @sync_new_received_anchor=0x0000000000000D4C
Beispiele für Aktualisierungs- und Löschbefehle finden Sie unter Vorgehensweise: Herunterladen inkrementeller Datenänderungen auf einen Client und unter Vorgehensweise: Bidirektionaler Austausch inkrementeller Datenänderungen zwischen Client und Server.
Wie oben ausgeführt, richtet sich der Befehl, der zum Abrufen der Ankerwerte verwendet wird, nach dem Datentyp der nachverfolgenden Spalten in der Serverdatenbank. Die Beispiele in dieser Dokumentation verwenden SQL Server-timestamp-Spalten, auch bekannt unter der Bezeichnung rowversion. Bei Verwendung einer SQL Server-datetime-Spalte würde die Abfrage für den neuen Ankerbefehl in etwa wie folgt aussehen:
SELECT @sync_new_received_anchor = GETUTCDATE()
Bei der Festlegung des für einen Anker zu verwendenden Datentyps sollten Sie die Anforderungen für die Anwendung abwägen und überlegen, wie flexibel Sie bei der Änderung des Serverdatenbankschemas sind. Wenn die Datenbank sich noch in der Entwicklung befindet, können Sie genau festlegen, welche Spalten und Trigger hinzugefügt werden sollen. Bei Produktionsdatenbanken sind Ihnen die Hände jedoch u. U. stärker gebunden. Halten Sie sich bei Ihren Überlegungen an die folgenden Richtlinien:
Alle Tabellen in einer Synchronisierungsgruppe sollten den gleichen Datentyp und einen neuen Ankerbefehl verwenden. Wenn möglich, verwenden Sie für alle Gruppen den gleichen Datentyp und Befehl.
Der datetime-Datentyp ist einfach zu verstehen, und Tabellen besitzen häufig bereits eine Spalte, die nachverfolgt, wann eine Zeile geändert wurde. Dennoch kann dieser Datentyp zu Problemen führen, nämlich dann, wenn sich die Clients in verschiedenen Zeitzonen befinden. Wenn Sie diesen Datentyp verwenden, könnten beim Auswählen inkrementeller Änderungen Transaktionen ausgelassen werden.
Der timestamp-Datentyp ist präzise und nicht von der Uhr abhängig. Jede Tabelle in einer SQL Server-Datenbank kann aber immer nur eine Spalte dieses Datentyps enthalten. Wenn Sie zwischen Einfügungen und Aktualisierungen unterscheiden müssen, können Sie daher eine Spalte eines anderen Datentyps, z. B. des binary(8)-Datentyps, hinzufügen und die Timestampwerte in dieser Spalte speichern. Ein Beispiel dafür finden Sie unter Setupskripts für Datenbankanbieter - Themen zur Vorgehensweise. Der timestamp-Datentyp könnte zu einem Problem werden, wenn die Serverdatenbank aus einer Sicherung wiederhergestellt wird. Weitere Informationen dazu finden Sie unter Von Sync Framework unterstützte Datenbankobjekte. Wie weiter oben bereits erwähnt, empfehlen wir, MIN_ACTIVE_ROWVERSION im Befehl zu verwenden, der einen neuen Anker auswählt.
Identifizieren des Clients, der eine Datenänderung vorgenommen hat
Es gibt zwei Hauptgründe für die Identifizierung des Clients, der eine Datenänderung vorgenommen hat:
Unterstützung der Konflikterkennung und -auflösung bei Nur-Upload-Synchronisierungen und bei bidirektionalen Synchronisierungen
Wenn der Server und ein oder mehrere Clients eine bestimmte Zeile ändern können, möchten Sie u. U. wissen, wer die Änderung vorgenommen hat. Mit dieser Information können Sie Code schreiben, mit dem z. B. festgelegt wird, welcher Änderung der Vorzug gegeben werden soll. Wenn diese Information nicht vorliegt, bleibt die letzte Änderung der Zeile bestehen.
Vermeidung der Rückgabe von Änderungen während einer bidirektionalen Synchronisierung zum Client als Echo
Sync Framework lädt erst die Änderungen auf den Server hoch und dann Änderungen auf den Client herunter. Wenn die Identität des Clients, der die Änderung vorgenommen hat, nicht nachverfolgt wird, wird die Änderung auf den Server hochgeladen und dann im Verlauf derselben Synchronisierungssitzung wieder auf den Client heruntergeladen. Eine solche Echowirkung ist zwar mitunter akzeptabel, wird aber nicht in allen Fällen gewünscht.
Genau wie bei der Änderungsnachverfolgung schreibt Sync Framework auch für die Unterstützung der Identitätsnachverfolgung nichts Spezifisches vor. Auch hier gibt es aber eine gängige Methode für die Vorgehensweise. Gehen Sie für jede zu synchronisierende Tabelle wie folgt vor:
Fügen Sie der Basistabelle eine Spalte hinzu, die nachverfolgt, wer die jeweilige Einfügung vorgenommen hat.
Fügen Sie der Basistabelle eine Spalte hinzu, die nachverfolgt, wer die jeweilige Aktualisierung vorgenommen hat.
Fügen Sie der Tombstonetabelle eine Spalte hinzu, die nachverfolgt, wer die jeweilige Löschung vorgenommen hat.
Anhand dieser Spalten und Tabellen sowie der ClientId-Eigenschaft wird ermittelt, welcher Client die einzelnen Einfügungen, Aktualisierungen oder Löschungen vorgenommen hat. Bei der ersten Synchronisierung einer Tabelle, die nicht als Momentaufnahmensynchronisierung durchgeführt wird, speichert Sync Framework einen GUID-Wert auf dem Client, anhand dessen der Client identifiziert werden kann. Diese ID wird an den DbServerSyncProvider übergeben, sodass sie von den Auswahl- und Aktualisierungsabfragen im jeweiligen SyncAdapter verwendet werden kann. Der ID-Wert ist über die ClientId-Eigenschaft abrufbar. Betrachten wir dazu die folgende Transact-SQL-Abfrage:
SELECT CustomerId, CustomerName, SalesPerson, CustomerType FROM
Sales.Customer WHERE InsertTimestamp > @sync_last_received_anchor AND
InsertTimestamp <= @sync_new_received_anchor AND InsertId <>
@sync_client_id
Diese Abfrage ähnelt der Abfrage weiter oben, die Einfügungen nachverfolgt, die auf dem Server gemacht werden. Die Anweisung in der WHERE
-Klausel stellt sicher, dass nur die Einfügungen heruntergeladen werden, die nicht vom Client vorgenommen wurden, der gerade die Synchronisierung durchführt.
Mit Sync Framework können Anwendungen Clients auch identifizieren, indem sie anstelle eines GUID-Werts eine ganze Zahl auf dem Server verwenden. Weitere Informationen dazu finden Sie unter Vorgehensweise: Verwenden von Sitzungsvariablen.
Beispiele für die Servervorbereitung
In den folgenden Beispielen wird gezeigt, wie die Sales.Customer
-Tabelle in der Sync Framework-Beispieldatenbank mit der Nachverfolgungsinfrastruktur für die Behandlung des komplexesten Anwendungsszenarios versehen werden kann: bidirektionale Einfüge-, Aktualisierungs- und Löschvorgänge mit Konflikterkennung. Für weniger komplexe Szenarien ist nicht die gesamte Infrastruktur notwendig. Weitere Informationen dazu finden Sie unter "Servervoraussetzungen für Synchronisierungsszenarien" weiter oben. Ein vollständiges Skript, das die Objekte in diesem Beispiel sowie zusätzliche Objekte erstellt, finden Sie unter Setupskripts für Datenbankanbieter - Themen zur Vorgehensweise. Weitere Informationen zur Verwendung dieser Objekte finden Sie unter Vorgehensweise: Angeben der Synchronisierungsart (Momentaufnahmen-, Nur-Download-, Nur-Upload- oder bidirektionale Synchronisierung).
Die Beispiele in diesem Abschnitt führen die folgenden Schritte zur Vorbereitung des Servers aus:
Überprüfen des
Sales.Customer
-Schemas und Bestimmen, ob die Tabelle einen Primärschlüssel und Spalten aufweist, die zur Änderungsnachverfolgung verwendet werden könnenHinzufügen von Spalten für die Nachverfolgung des Zeitpunkts und Orts von Einfügungen und Aktualisierungen
Erstellen einer Tombstonetabelle und Hinzufügen eines Triggers zur
Sales.Customer
-Tabelle, um die Tombstonetabelle aufzufüllen
Überprüfen des "Sales.Customer"-Schemas
Im folgenden Codebeispiel wird das Schema der Sales.Customer
-Tabelle veranschaulicht. Die Tabelle verfügt in der CustomerId
-Spalte über einen Primärschlüssel, besitzt aber keine Spalten, die für die Änderungsnachverfolgung verwendet werden können.
CREATE TABLE SyncSamplesDb.Sales.Customer(
CustomerId uniqueidentifier NOT NULL PRIMARY KEY DEFAULT NEWID(),
CustomerName nvarchar(100) NOT NULL,
SalesPerson nvarchar(100) NOT NULL,
CustomerType nvarchar(100) NOT NULL)
Hinzufügen von Spalten zur Nachverfolgung von Einfüge- und Aktualisierungsvorgängen
Im folgenden Codebeispiel werden vier Spalten hinzugefügt: UpdateTimestamp
, InsertTimestamp
, UpdateId
und InsertId
. Die Spalte UpdateTimestamp
ist eine SQL Server-timestamp
-Spalte. Diese Spalte wird automatisch aktualisiert, wenn die Zeile aktualisiert wird. Wie bereits erwähnt, kann eine Tabelle immer nur eine timestamp
-Spalte besitzen. Deshalb ist die InsertTimestamp
-Spalte eine binary(8)
-Spalte mit dem Standardwert @@DBTS + 1
. Im Beispiel wird der Wert erhöht, der von @@DBTS
zurückgegeben wird, sodass die Spalten UpdateTimestamp
und InsertTimestamp
nach einem Einfügevorgang denselben Wert enthalten. Wenn dies nicht geschehen würde, entstünde der Eindruck, dass jede Zeile nach dem Einfügen aktualisiert wurde.
Die ID, die Sync Framework für jeden Client erstellt, ist eine GUID. Die beiden ID-Spalten sind daher uniqueidentifier
-Spalten. Der Standardwert dieser Spalten lautet 00000000-0000-0000-0000-000000000000
. Dieser Wert gibt an, dass der Server die Aktualisierung oder Einfügung ausgeführt hat. In einem späteren Beispiel enthält die Tombstonetabelle eine DeleteId
-Spalte.
ALTER TABLE SyncSamplesDb.Sales.Customer
ADD UpdateTimestamp timestamp
ALTER TABLE SyncSamplesDb.Sales.Customer
ADD InsertTimestamp binary(8) DEFAULT @@DBTS + 1
ALTER TABLE SyncSamplesDb.Sales.Customer
ADD UpdateId uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'
ALTER TABLE SyncSamplesDb.Sales.Customer
ADD InsertId uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'
Nachdem die Spalten hinzugefügt wurden, werden mit dem folgenden Beispielcode Indizes hinzugefügt. Diese und andere Indizes im Beispielcode werden auf der Grundlage der Spalten erstellt, die während der Synchronisierung abgefragt werden. Die Indizes werden hinzugefügt, um Sie daran zu erinnern, dass bei der Implementierung einer Änderungsnachverfolgung in der Serverdatenbank auch an die Indizes gedacht werden sollte. Sie sollten in jedem Fall die Serverleistung gegen die Synchronisierungsleistung abwägen.
CREATE NONCLUSTERED INDEX IX_Customer_UpdateTimestamp
ON Sales.Customer(UpdateTimestamp)
CREATE NONCLUSTERED INDEX IX_Customer_InsertTimestamp
ON Sales.Customer(InsertTimestamp)
CREATE NONCLUSTERED INDEX IX_Customer_UpdateId
ON Sales.Customer(UpdateId)
CREATE NONCLUSTERED INDEX IX_Customer_InsertId
ON Sales.Customer(InsertId)
Hinzufügen einer Tombstonetabelle zur Nachverfolgung von Löschvorgängen
Das folgende Codebeispiel erstellt eine Tombstonetabelle, die einen gruppierten Index und einen Trigger zum Ausfüllen der Tabelle enthält. Wenn in der Sales.Customer
-Tabelle ein Löschvorgang abläuft, fügt der Trigger eine Zeile in die Sales.Customer_Tombstone
-Tabelle ein. Bevor der Trigger einen Einfügevorgang ausführt, prüft er, ob die Sales.Customer_Tombstone
-Tabelle bereits eine Zeile mit dem Primärschlüssel einer gelöschten Zeile enthält. Dies kann der Fall sein, wenn eine Zeile aus Sales.Customer
gelöscht, wieder eingefügt und dann erneut gelöscht wurde. Wenn der Trigger eine solche Zeile in Sales.Customer_Tombstone
findet, löscht er die Zeile und fügt sie wieder ein. Die DeleteTimestamp
-Spalte in Sales.Customer_Tombstone
könnte ebenfalls aktualisiert werden.
CREATE TABLE SyncSamplesDb.Sales.Customer_Tombstone(
CustomerId uniqueidentifier NOT NULL PRIMARY KEY NONCLUSTERED,
CustomerName nvarchar(100) NOT NULL,
SalesPerson nvarchar(100) NOT NULL,
CustomerType nvarchar(100) NOT NULL,
DeleteId uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
DeleteTimestamp timestamp)
CREATE TRIGGER Customer_DeleteTrigger
ON SyncSamplesDb.Sales.Customer FOR DELETE
AS
BEGIN
SET NOCOUNT ON
DELETE FROM SyncSamplesDb.Sales.Customer_Tombstone
WHERE CustomerId IN (SELECT CustomerId FROM deleted)
INSERT INTO SyncSamplesDb.Sales.Customer_Tombstone (CustomerId, CustomerName, SalesPerson, CustomerType)
SELECT CustomerId, CustomerName, SalesPerson, CustomerType FROM deleted
SET NOCOUNT OFF
END
CREATE CLUSTERED INDEX IX_Customer_Tombstone_DeleteTimestamp
ON Sales.Customer_Tombstone(DeleteTimestamp)
CREATE NONCLUSTERED INDEX IX_Customer_Tombstone_DeleteId
ON Sales.Customer_Tombstone(DeleteId)