コラボレーション同期用にサーバー データベースを準備する方法 (SQL Server 以外)

注意

ドキュメントの「他の ADO.NET 互換データベースの同期」セクションでは、Sync Framework を使用して SQL Server 以外のデータベースを同期する方法を紹介します。このリリースのコード例では SQL Server が使用されていますが、SQL Server 固有のオブジェクト (SqlConnection など) や SQL クエリを一部変更することで、他の ADO.NET 互換データベースでも同じコードを使用できます。SQL Server の同期については、「コラボレーション同期を構成して実行する方法 (SQL Server)」を参照してください。

このトピックでは、DbSyncProvider によるデータベースの同期という前提で、データの増分変更を追跡できるような形でデータベースを準備する方法について説明します。変更を追跡することによって、同期セッション中、それらの変更を他のノードに適用することができます。Sync Framework 用にデータベースを準備するには、次の手順に従います。

  1. データベースのスナップショット分離を有効にします。

  2. 同期するテーブルを決めます。

  3. テーブル単位のメタデータを保存する追跡テーブルを作成し、それらのテーブルにインデックスを作成します。

  4. 追跡テーブルにデータを取り込んだり、それらのデータを更新したりするためのトリガーを各ベース テーブルに作成します。

  5. (省略可) データベース内の既存のデータを処理します。

  6. スコープ単位のメタデータを保存する追跡テーブルを作成し、そのテーブルにインデックスを作成します。

  7. 同期するスコープを定義します。つまり、1 つの単位として同期する複数のテーブルを指定します。

  8. データおよびメタデータの選択と更新を行うストアド プロシージャを作成します。

SqlCeSyncProvider によって同期されるデータベースの場合、上記の手順は不要です。データベースの初期化時に、Sync Framework によって準備されます。

データベースの準備が済むと、そのデータベースを他のノードと同期できるようになります。同期の構成方法と実行方法については、「コラボレーション同期を構成して実行する方法 (SQL Server 以外)」を参照してください。

データベースのスナップショット分離を有効にする

同期セッションの変更列挙フェーズ中、Sync Framework はスナップショット分離下でトランザクションを開始します。スナップショット分離下でトランザクションを開始するには、ALLOW_SNAPSHOT_ISOLATION データベース オプションを ON に設定します。そのコード例を次に示します。

ALTER DATABASE [database name] SET ALLOW_SNAPSHOT_ISOLATION ON

詳細については、SQL Server オンライン ブックを参照してください。

同期するテーブルを決める

データベースを準備する際の最初の手順は、同期の対象となるテーブルを決めることです。各テーブルは、主キーを必要とします。次のコード例について考えてみます。このコード例は、SyncSamplesDb_Peer1 データベースの Sales.Customer テーブル スキーマを示します。

CREATE TABLE 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)

同期するテーブルにはそれぞれ DbSyncAdapter オブジェクトが関連付けられ、そのオブジェクトの RowIdColumns コレクション内の主キーを指定することになります。詳細については、「コラボレーション同期を構成して実行する方法 (SQL Server 以外)」を参照してください。

テーブルは空でも、既存のデータが存在していてもかまいません。既にデータ行が挿入されているテーブルを同期する場合、それらの各行のメタデータ エントリが該当する変更追跡テーブルに存在している必要があります。詳細については、「データベース内の既存のデータを処理する」を参照してください。

テーブル単位のメタデータ用の追跡テーブルを作成する

Sync Framework では、2 つのノード間で同期セッションを実行した後、どの行が変更されたかを追跡するための方法が必要になります。変更は次の 2 種類のメタデータによって表されます。

  • テーブル単位のメタデータ: 同期対象のテーブルごとに、データの挿入、更新、および削除を追跡します。

  • スコープ単位のメタデータ: 各ノードが他のノードから受け取った変更を追跡します。

テーブル単位でのメタデータの追跡では、ベース テーブルごとに 1 つの追跡テーブルが使用されます。ベース テーブルと追跡テーブルは、DbSyncProvider によって同期される各データベースに存在する必要があります。追跡テーブルの主キーはベース テーブルのものと同じです。また、それ以外にも列が必要となります。これらの列を次の表に詳しく示します。追加の列の名前は、この一覧の名前と同じである必要はありません。ただし、列の順序および型については、追跡テーブルにアクセスするクエリまたはプロシージャと一致している必要があります。これらのプロシージャのいくつかについては、「データおよびメタデータの選択と更新を行うストアド プロシージャを作成する」に記載されています。

説明 更新のタイミング

<ベース テーブルの主キー (PK)>: PK 列ごとに列を追加

ベース テーブルの主キー列。

ベース テーブルに行が挿入されたとき。ローカル ノードで挿入された場合、またはリモート ノードによって挿入された場合が対象となります。

update_scope_local_id

前回更新または削除を実行したスコープの ID。更新または削除がローカル ノードで発生した場合、この列は NULL です。

スコープ情報テーブルの scope_local_id 列が参照されます。詳細については、「スコープ単位のメタデータ用の追跡テーブルを作成する」を参照してください。

リモート ノードによる更新または削除がベース テーブルに適用されたとき。

scope_update_peer_key

前回更新または削除を実行したノードの ID。

リモート ノードによる更新または削除がベース テーブルに適用されたとき。

scope_update_peer_timestamp

リモート データベースで行が更新または削除されたときの、リモート データベースのタイムスタンプ値。

リモート ノードによる更新または削除がベース テーブルに適用されたとき。

local_update_peer_key

ローカル ノードの ID。ローカル データベースをバックアップから復元した場合でない限り、どの行についても、この列には値 0 が格納されます。1

ローカル ノードまたはリモート ノードによる更新や削除がベース テーブルに適用されたとき。

local_update_peer_timestamp

ローカル データベースで行が更新または削除されたときの、ローカル データベースのタイムスタンプ値。1

ローカル ノードまたはリモート ノードによる更新や削除がベース テーブルに適用されたとき。

create_scope_local_id

挿入を実行したスコープの ID。更新または削除がローカル ノードで発生した場合、この列は NULL です。

スコープ情報テーブルの scope_local_id 列が参照されます。詳細については、「コラボレーション同期用にサーバー データベースを準備する方法 (SQL Server 以外)」の「スコープ単位のメタデータ用の追跡テーブルを作成する」を参照してください。

リモート ノードによるデータ挿入がベース テーブルに適用されたとき。

scope_create_peer_key

挿入を実行したノードの ID。

リモート ノードによるデータ挿入がベース テーブルに適用されたとき。

scope_create_peer_timestamp

リモート データベースで行が挿入されたときの、リモート データベースのタイムスタンプ値。

リモート ノードによるデータ挿入がベース テーブルに適用されたとき。

local_create_peer_key

ローカル ノードの ID。ローカル データベースをバックアップから復元した場合でない限り、どの行についても、この列には値 0 が格納されます。1

ローカル ノードまたはリモート ノードによるデータ挿入がベース テーブルに適用されたとき。

local_create_peer_timestamp

行がローカル データベースに挿入されたときの、ローカル データベースのタイムスタンプ値。1

ローカル ノードまたはリモート ノードによるデータ挿入がベース テーブルに適用されたとき。

sync_row_is_tombstone

値 1 は、メタデータ エントリがベース テーブルでの削除用であることを示します。

ベース テーブルから行が削除されたとき。ローカル ノードで削除された場合、またはリモート ノードによって削除された場合が対象となります。

last_change_datetime

メタデータ行の最終更新日時。

この追跡テーブル内の行が挿入または更新されたとき。

restore_timestamp

local_update_peer_timestamp の値はデータベースの復元時に保存されます。この値はさらに、ローカルの更新タイムスタンプ値として使用されます。

通常は NULL ですが、復元プロセスで設定できます。行が更新されると常に NULL に設定されます。

<フィルター列>: 任意のスコープのフィルター選択 (WHERE 句) に使用される非 PK 列ごとに列を追加。

1 つ以上のスコープについてテーブルをフィルター選択する場合のみ必要となります。挿入、更新、および削除の対象としてフィルター選択された列の値が格納されます。

ベース テーブルの行が挿入、更新、または削除されたとき。ローカル ノードで削除された場合、またはリモート ノードによって削除された場合が対象となります。

1 オーバーラップするスコープの同期時に、Sync Framework によって使用されます。たとえば、データベースを更新する際、スコープ X をクライアント A と同期し、スコープ Y をクライアント B と同期するとします。どちらのスコープにも行 Q が含まれています。

  1. 行 Q がクライアント A で更新され、その後、データベースと同期されます。

  2. クライアント B はデータベースと同期し、行 Q に対する更新を受け取ります。

    クライアント B はスコープ X を認識しません。そのため、クライアント A による変更は、あたかもデータベースで行われたかのように見えます。これは、クライアント B (または行 Q の update_scope_local_id に格納されたスコープを同期しない他のあらゆるクライアント) との同期時に、local_update_peer_key および local_update_peer_timestamp の値を使用することによって実現されます。

  3. 行 Q がデータベースで更新され、その後、クライアント A と同期されます。

    クライアント A はスコープ X を認識します。そのため、クライアント A (またはスコープ X と同期する他のあらゆるクライアント) との同期時には、scope_update_peer_key および scope_update_peer_timestamp の値が使用されます。

追跡テーブルなど、同期メタデータに関連するすべてのオブジェクトについては、データベース スキーマを別に作成することをお勧めします。これにより、メタデータと、ベース テーブル内のデータとを分離することができます。パフォーマンスを最適化するために、各追跡テーブルにはインデックスを作成します。

  • データをフィルター選択しない場合: ベース テーブルと同じ主キーを使用、非クラスター化インデックスの作成対象: (local_update_peer_timestamp)

  • データをフィルター選択する場合: ベース テーブルと同じ主キーを使用、非クラスター化インデックスの作成対象: (local_update_peer_timestamp、<フィルター列>、<主キー列>)

次のコード例は、Sync スキーマに、Sales.Customer テーブルの変更を追跡するテーブルを作成し、このテーブルにインデックスを追加します。

CREATE TABLE Sync.Customer_Tracking(
    
    CustomerId uniqueidentifier NOT NULL PRIMARY KEY,          
    
    update_scope_local_id int NULL, 
    scope_update_peer_key int,
    scope_update_peer_timestamp bigint,
    local_update_peer_key int,
    local_update_peer_timestamp timestamp,

    create_scope_local_id int NULL,
    scope_create_peer_key int,
    scope_create_peer_timestamp bigint,
    local_create_peer_key int,
    local_create_peer_timestamp bigint,

    sync_row_is_tombstone int, 
    restore_timestamp bigint, 
    last_change_datetime datetime default NULL)

CREATE NONCLUSTERED INDEX NonClustered_Customer_Tracking
ON Sync.Customer_Tracking ([local_update_peer_timestamp])

追跡テーブルにデータを取り込んだり、それらのデータを更新したりするためのトリガーを作成する

追跡テーブルを作成したら、INSERT、UPDATE、および DELETE のトリガーを各ベース テーブルに追加します。ユーザーまたは Sync Framework によってベース テーブルの行が挿入、更新、または削除されると、トリガーが作動し、変更追跡テーブル内でも該当行のメタデータが挿入または更新されます。Sync Framework が (別のノードから受け取った) 変更をベース テーブルに適用した場合、Sync Framework は変更追跡テーブルを更新して、それがどこで発生した変更なのかを明らかにします。

次のコード例では、Sales.Customer テーブルに更新が加えられたときに Sales.Customer_Tracking テーブルの変更追跡メタデータを更新する、トリガーを作成します。挿入トリガーおよび削除トリガーの例については、「データベース プロバイダーのセットアップ スクリプトに関するトピック」を参照してください。

CREATE TRIGGER Customer_UpdateTrigger ON Sales.Customer FOR UPDATE
AS    
    UPDATE t    
    SET 
        update_scope_local_id = NULL, local_update_peer_key = 0, 
        restore_timestamp = NULL, last_change_datetime = GetDate() 
    FROM Sync.Customer_Tracking t JOIN inserted i ON t.[CustomerId] = i.[CustomerId]        

データベース内の既存のデータを処理する

各テーブルの変更追跡メタデータは、ベース テーブル上のトリガーによって挿入および更新されます。したがって、トリガーが追加される前にベース テーブルに挿入された行に関する情報は、変更追跡テーブルに存在しません。データベース内の既存のデータを処理するには、既存のデータに対応するメタデータを挿入する必要があります。すると、初回同期セッション時に、すべての行が新しい挿入操作として、同期先のデータベースに送信されます。次のコード例は、ベース テーブルにトリガーを追加した後、各ベース テーブルについて実行するコマンドです。

INSERT INTO [tracking table] ([pk columns], create_scope_local_id, local_create_peer_key, local_create_peer_timestamp, update_scope_local_id, local_update_peer_key, restore_timestamp, sync_row_is_tombstone)
SELECT [pk columns], NULL, 0, @@DBTS+1, NULL, 0, NULL, 0 from [base table] baseT left outer join [tracking table] trackingT
On baseT.[pk columns]=trackingT.[pk columns]
where tracking.[pk columns] is null

スコープ単位のメタデータ用の追跡テーブルを作成する

スコープ単位のメタデータは、通常、各データベースの 2 つのテーブルを使用して追跡されます。

  • スコープ情報テーブル: 各スコープの同期情報がバイナリ形式で保存されます。スコープとは複数のテーブルを論理的にグループ化したものであり、それらのデータが 1 つの単位として同期されます。

  • スコープ マッピング テーブル: データベース内のどのテーブルがどのスコープに属するかを特定します。1 つのテーブルが複数のスコープに属している場合もあります。マッピング テーブルには、<scope, table> のペアごとに 1 つのエントリを作成します。

同期中、Sync Framework は、各データベースに送信する変更をナレッジを使用して特定します。アプリケーションでナレッジを直接操作する必要はありません。3 つのノードを含む双方向同期トポロジを考えてみます。

  1. ノード 1 とノード 2 の間ですべての変更が同期されます。

  2. ノード 1 はノード 3 と同期します。

  3. ユーザーがノード 2 でデータを更新します。

  4. ノード 3 はノード 2 と同期します。

ノード 3 がノード 2 と同期する時点で、ノード 3 にはノード 2 のほとんどの変更が既に適用されています。これは、最初にノード 3 がノード 1 と同期しているためです。ナレッジを利用することで、Sync Framework はこれを認識し、ノード 2 で加えられた更新のみを同期できます。ナレッジの詳細については、「同期ナレッジについて」を参照してください。

次の表で、スコープ情報テーブルの各列について説明します。

説明 更新のタイミング

scope_id

スコープの識別子 (通常は GUID)。

更新されない。

scope_local_id

スコープの整数識別子。これは IDENTITY 列であることが必要です。

更新されない。

scope_name

スコープの名前。

更新されない。

scope_sync_knowledge

各スコープの同期ナレッジのバイナリ表現。

すべての変更が同期セッションの同期先に適用されたとき。

scope_tombstone_cleanup_knowledge

各スコープの "忘れられたナレッジ" バイナリ表現。忘れられたナレッジは、クリーンアップされたメタデータに使用されます。

すべての変更が同期セッションの同期先に適用されたとき。

scope_timestamp

メタデータ行が前回更新されたときのタイムスタンプ値。

この追跡テーブル内の行が更新されたとき。

scope_cleanup_timestamp

このスコープに対して、廃棄標識のクリーンアップが最後に実行されたときのタイムスタンプ値。

オーバーラップするテーブルを持つ別のスコープの廃棄標識がクリーンアップされたとき。

次のコード例では、スコープ情報テーブルを作成します。

CREATE TABLE Sync.ScopeInfo(       
    scope_local_id int IDENTITY(1,1),
    scope_id uniqueidentifier default NEWID(),
    scope_name nvarchar(100) NOT NULL PRIMARY KEY,
    scope_sync_knowledge varbinary(max) NULL,
    scope_tombstone_cleanup_knowledge varbinary(max) NULL,
    scope_timestamp timestamp,
    scope_cleanup_timestamp bigint)

特定のスコープに関する情報を取得するときは、ほとんどの場合、対象スコープの名前に基づいてスコープ情報テーブルが照会されます。したがって、主キーは scope_name 列に定義します。

次の表でスコープ マッピング テーブルの各列について説明します。

説明 更新のタイミング

table_name

テーブルの名前。

更新されない

scope_name

スコープの名前。

更新されない

次のコード例は、スコープ マッピング テーブルを作成し、そのテーブルにインデックスを作成しています。

CREATE TABLE Sync.ScopeTableMap(       
    scope_name nvarchar(100) ,
    table_name nvarchar(100)     
    )

CREATE UNIQUE CLUSTERED INDEX Clustered_ScopeTableMap ON Sync.ScopeTableMap(scope_name, table_name)

同期するスコープを定義する

スコープ テーブルを作成したら、同期するスコープを少なくとも 1 つ決定します。たとえば、Sales という名前のスコープを定義し、そのスコープに CustomerCustomerContactOrderHeaderOrderDetail という 4 つのテーブルを定義します。Sales スコープを同期すると、これら 4 つのテーブルに対する変更が 2 つのノード間で交換されます。スコープの定義は、次の 2 段階から成るプロセスです。

  1. スコープ情報テーブルおよびスコープ マッピング テーブルにエントリを追加します (次のコード例を参照)。

    INSERT INTO Sync.ScopeInfo(scope_name) VALUES (''Sales'')
    INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.Customer'')
    INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.CustomerContact'')
    
  2. DbSyncProvider オブジェクトの ScopeName プロパティに対してスコープ名を指定し、そのスコープに含める各テーブルについて DbSyncAdapter オブジェクトを追加します。詳細については、「コラボレーション同期を構成して実行する方法 (SQL Server 以外)」の「ScopeName および Connection のアプリケーション コード」を参照してください。

注意

スコープを最初に同期した後は、そのスコープを変更しないでください。スコープ内のテーブルを変更したり、それらのテーブルに対するフィルター選択句を変更したりすると、データの非収束を招く可能性があります。

フィルター選択されたスコープとオーバーラップするスコープ

ベース テーブルの一部の行のみがスコープに含まれている場合、そのスコープは "フィルター選択" されています。たとえば、フィルター選択を適用し、ワシントン州の売上データだけを含む sales-WA スコープを定義できます。データをフィルター選択するには、DbSyncAdapter オブジェクトの SelectIncrementalChangesCommand プロパティに対して指定したクエリまたはプロシージャに、適切なデータを選択する WHERE 句が含まれている必要があります。クエリまたはプロシージャは、ベース テーブルのフィルター列ではなく、追跡テーブルのフィルター列に基づいて変更を選択する必要があります。

次の種類のフィルター選択はサポートされません。

  • 列のフィルター選択: 変更を選択して適用するクエリまたはプロシージャでは、すべての列が処理の対象になっている必要があります。

  • フィルター選択で使用される列の更新: フィルター選択で使用される列の値をユーザーが更新した場合、行が別のスコープに移動します。この行は、新しい所属先スコープに追加されますが、それまでのスコープからも削除されません。

2 つのスコープが同じデータを共有している場合、"2 つのスコープがオーバーラップしている" といいます。たとえば、products テーブルが sales スコープに属しており、さらに inventory スコープにも属している状況が考えられます。スコープがオーバーラップし、なおかつフィルター選択されている状況もありえます。フィルター選択とオーバーラップの両方が起こるシナリオを次に示します。

  • シナリオ 1:

    • スコープ 1 は sales-WA です。このスコープには、productsorders (フィルター: state=WA)、および order_details (フィルター: state=WA) が含まれます。

    • スコープ 2 は sales-OR です。このスコープには、productsorders (フィルター: state=OR)、および order_details (フィルター: state=OR) が含まれます。

    このシナリオでは、products テーブル全体が両方のスコープによって共有されています。orders テーブルと order_details テーブルは両方のスコープに存在しますが、フィルターはオーバーラップしていないため、これらのスコープは、これらのテーブルの行を共有しません。

  • シナリオ 2:

    • スコープ 1 は sales-WA です。このスコープには、productsorders (フィルター: state=WA)、および order_details (フィルター: state=WA) が含まれます。

    • スコープ 2 は sales-Northwest です。このスコープには、productsorders (フィルター: state=WA OR state=ID) および shippers が含まれます。

    このシナリオでも、products テーブル全体が両方のスコープによって共有されています。orders テーブルは両方のスコープに存在し、フィルターはオーバーラップしています。つまり、両方のスコープが state=WA というフィルターを満たした行を共有することになります。shippers テーブルと order_details テーブルはスコープ間で共有されません。

スコープはさまざまな方法で定義できますが、必ず、次の原則に従う必要があります。同期トポロジ内の 2 つのデータベース間で同期されるデータは、1 つのスコープにしか所属できない、ということです。たとえば、先ほどのシナリオ 2 の場合、データベース A とデータベース B はスコープ 1 を同期できます。データベース A とデータベース C はスコープ 2 を同期できます。しかし、データベース A とデータベース B が (スコープ 1 に加え) スコープ 2 を同期することはできません。productsorders には、両方のスコープに属している行が存在するためです。

データおよびメタデータの選択と更新を行うストアド プロシージャを作成する

メタデータ テーブルを作成した後は、変更を選択してベース テーブルおよびメタデータ テーブルに適用するための SQL クエリまたはストアド プロシージャ (推奨) を作成します。パフォーマンスおよびセキュリティ上の理由から、ストアド プロシージャをお勧めします。これらのクエリまたはプロシージャは、次の DbSyncAdapter コマンドに指定します。これらのコマンドの詳細については、「コラボレーション同期を構成して実行する方法 (SQL Server 以外)」の「同期アダプター」を参照してください。

次のコード例では、Sales.Customer テーブルのデータおよびメタデータの変更を処理するための一連のストアド プロシージャを作成します。説明を簡単にするために、データを選択するためのプロシージャと更新を処理するためのプロシージャが含まれていますが、挿入および削除のためのプロシージャは含まれていません。挿入プロシージャおよび削除プロシージャの例については、「データベース プロバイダーのセットアップ スクリプトに関するトピック」を参照してください。テンプレートを使用すると、こうしたストアド プロシージャをすべて簡単に作成できます。テンプレートについては「サーバーの準備のテンプレート」を参照してください。

このトピックの末尾にある完全なコード例において、これらのプロシージャに渡される値の多くは、"セッション変数" から取得されます。Sync Framework は、これらの組み込み変数を使用して、同期セッション中に値をコマンドに渡すことができます。セッション変数の詳細については、「コラボレーションでの同期でセッション変数を使用する方法」を参照してください。

SelectIncrementalChangesCommand のプロシージャ

create procedure Sync.sp_Customer_SelectChanges (
    @sync_min_timestamp bigint,
    @sync_metadata_only int,
    @sync_scope_local_id int,
    @sync_initialize int
)
as

--if @sync_initialize = 0
--begin
    -- Perform additional logic if required.
--end
    
begin
    select  t.CustomerId, 
            c.CustomerName,
            c.SalesPerson,
            c.CustomerType, 
            t.sync_row_is_tombstone,
            t.local_update_peer_timestamp as sync_row_timestamp, 
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
    from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId
    where t.local_update_peer_timestamp > @sync_min_timestamp
end

UpdateCommand のプロシージャ

CREATE PROCEDURE Sync.sp_Customer_ApplyUpdate (                                    
        @CustomerId uniqueidentifier,
        @CustomerName nvarchar(100),
        @SalesPerson nvarchar(100),
        @CustomerType nvarchar(100),
        @sync_min_timestamp bigint ,                                
        @sync_row_count int OUT,
        @sync_force_write int)        
AS      
    UPDATE c
    SET c.CustomerName = @CustomerName, c.SalesPerson = @SalesPerson, c.CustomerType = @CustomerType      
    FROM Sales.Customer c JOIN Sync.Customer_Tracking t ON c.CustomerId = t.CustomerId
    WHERE ((t.local_update_peer_timestamp <= @sync_min_timestamp) OR @sync_force_write = 1)
        AND t.CustomerId = @CustomerId  
    SET @sync_row_count = @@rowcount

UpdateMetadataCommand のプロシージャ

create procedure Sync.sp_Customer_UpdateMetadata (
        @CustomerId uniqueidentifier,
        @sync_scope_local_id int,
        @sync_row_is_tombstone int,
        @sync_create_peer_key int,
        @sync_create_peer_timestamp bigint,                 
        @sync_update_peer_key int,
        @sync_update_peer_timestamp timestamp,                      
        @sync_row_timestamp timestamp,
        @sync_check_concurrency int,        
        @sync_row_count int out)        
as  
    declare @was_tombstone int
    select @was_tombstone = sync_row_is_tombstone from Sync.Customer_Tracking 
    where CustomerId = @CustomerId
    
    if (@was_tombstone is not null and @was_tombstone=1 and @sync_row_is_tombstone=0)
        -- tombstone is getting resurrected, update creation version as well
        update Sync.Customer_Tracking set
            [update_scope_local_id] = @sync_scope_local_id, 
            [scope_update_peer_key] = @sync_update_peer_key,
            [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
            [local_update_peer_key] = 0,
            [restore_timestamp] = NULL,
            [create_scope_local_id] = @sync_scope_local_id, 
            [scope_create_peer_key] = @sync_create_peer_key, 
            [scope_create_peer_timestamp] =  @sync_create_peer_timestamp, 
            [sync_row_is_tombstone] = @sync_row_is_tombstone                        
        where CustomerId = @CustomerId          
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    else    
        update Sync.Customer_Tracking set
            [update_scope_local_id] = @sync_scope_local_id, 
            [scope_update_peer_key] = @sync_update_peer_key,
            [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
            [local_update_peer_key] = 0,
            [restore_timestamp] = NULL,
            [sync_row_is_tombstone] = @sync_row_is_tombstone                        
        where CustomerId = @CustomerId          
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    set @sync_row_count = @@rowcount

SelectRowCommand のプロシージャ

create procedure Sync.sp_Customer_SelectRow
        @CustomerId uniqueidentifier,
        @sync_scope_local_id int
as
    select  t.CustomerId, 
            c.CustomerName,
            c.SalesPerson,
            c.CustomerType, 
            t.sync_row_is_tombstone,
            t.local_update_peer_timestamp as sync_row_timestamp, 
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
    from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId    
    where c.CustomerId = @CustomerId 

SelectMetadataForCleanupCommand のプロシージャ

CREATE PROCEDURE Sync.sp_Customer_SelectMetadata     
    @metadata_aging_in_days int,
    @sync_scope_local_id int
AS
    IF @metadata_aging_in_days = -1
        BEGIN
            SELECT  CustomerId,
                    local_update_peer_timestamp as sync_row_timestamp,  
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
            FROM Sync.Customer_Tracking
            WHERE sync_row_is_tombstone = 1
        END
    
    ELSE
        BEGIN
            SELECT  CustomerId,
                    local_update_peer_timestamp as sync_row_timestamp,  
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
            FROM Sync.Customer_Tracking
            WHERE sync_row_is_tombstone = 1 AND
            DATEDIFF(day, last_change_datetime, GETDATE()) > @metadata_aging_in_days
        END

結論

このトピックでは、変更追跡の対象となるデータベースを準備する手順を取り上げました。データベースの準備が済むと、そのデータベースを他のノードと同期できるようになります。同期の構成方法と実行方法の詳細については、「コラボレーション同期を構成して実行する方法 (SQL Server 以外)」を参照してください。

参照

概念

他の ADO.NET 互換データベースの同期
コラボレーション同期を構成して実行する方法 (SQL Server 以外)