Как подготовить серверную базу данных для синхронизации совместной работы (не SQL Server)

Примечание

В этом разделе документации Синхронизация других баз данных, совместимых с ADO.NET демонстрируется, как можно выполнить синхронизацию баз данных, отличных от SQL Server, посредством Sync Framework. В этой версии в примерах кода используется SQL Server, но сам код можно использовать для других, совместимых с ADO.NET, баз данных с некоторыми изменениями специфических объектов SQL Server (например, SqlConnection) и отображаемых SQL-запросов. Дополнительные сведения о синхронизации SQL Server см. в разделе Как настроить и выполнить синхронизацию базы данных (SQL Server).

В этом разделе описывается подготовка базы данных, которая синхронизируется посредством DbSyncProvider, к отслеживанию добавочных изменений данных. Изменения отслеживаются таким образом, что их можно применять к другим узлам в ходе сеанса синхронизации. Чтобы подготовить базу данных для Sync Framework, выполните следующие действия.

  1. Включите изоляцию моментального снимка для базы данных.

  2. Определите таблицы для синхронизации.

  3. Создайте таблицы отслеживания для хранения метаданных каждой таблицы и создайте индексы в этих таблицах.

  4. Создайте для каждой базовой таблицы триггеры для заполнения и обновления таблиц отслеживания.

  5. (Необязательно) Обработайте существующие данные в базе данных.

  6. Создайте таблицу отслеживания для хранения метаданных уровня области и постройте для этой таблицы индекс.

  7. Определите области синхронизации, которые указывают, какие таблицы синхронизируются как единое целое.

  8. Создайте хранимые процедуры для выбора и обновления данных и метаданных.

Эти действия не требуются для баз данных, которые синхронизируются посредством SqlCeSyncProvider; провизионирование выполняется Sync Framework при инициализации базы данных.

После подготовки базы данных можно выполнить ее синхронизации с другими узлами. Дополнительные сведения о настройке и выполнении синхронизации см. в разделе Как настроить и выполнить синхронизацию совместной работы (не SQL Server).

Включение изоляции моментального снимка для базы данных

На этапе перечисления изменений в сеансе синхронизации Sync Framework запускают транзакции в режиме изоляции моментального снимка. Чтобы запускать транзакции в режиме изоляции моментального снимка, необходимо установить параметр базы данных ALLOW_SNAPSHOT_ISOLATION в значение ON, как показано в следующем примере кода.

ALTER DATABASE [database name] SET ALLOW_SNAPSHOT_ISOLATION ON

Дополнительные сведения см. в электронной документации по SQL Server.

Определение таблиц для синхронизации

Первым этапом в провизионировании базы данных является определение таблиц для синхронизации. Каждая таблица должна иметь первичный ключ. Рассмотрим следующий пример программного кода. В нем показана схема таблицы Sales.Customer базы данных SyncSamplesDb_Peer1.

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 необходим способ отслеживания строк, измененных с последнего сеанса синхронизации между двумя узлами. Изменения представлены двумя типами метаданных.

  • Метаданные на уровне таблиц, отслеживающие операции вставки, обновления и удаления для каждой синхронизируемой таблицы.

  • Метаданные на уровне области, которые отслеживают изменения, полученные каждым узлом с других узлов.

Для отслеживания метаданных на уровне таблиц применяется одна таблица отслеживания для каждой базовой таблицы. Базовая таблица и таблицы отслеживания должны находиться в каждой базе данных, синхронизируемой посредством DbSyncProvider. Первичный ключ таблицы отслеживания тот же, что и в базовой таблице, а дополнительные столбцы являются обязательными. Описание этих столбцов приведено в следующей таблице. Имена дополнительных столбцов необязательно должны совпадать с указанными, однако их порядок и тип должны соответствовать запросам или процедурам, обращающимся к таблицам отслеживания. Некоторые из этих процедур включены в раздел Создание хранимых процедур для выбора и обновления данных и метаданных.

Столбец

Описание

Обновляется, когда…

<Первичный ключ базовой таблицы> — включите столбец для каждого столбца первичного ключа.

Столбцы первичного ключа базовой таблицы.

Строка вставляется в базовую таблицу. Вставка может происходить с локального или удаленного узла.

update_scope_local_id

Идентификатор области, выполнившей последнее обновление или удаление. Для обновлений или удалений, выполняемых на локальном узле, значение данного столбца равно NULL.

Относится к столбцу scope_local_id в таблице сведений области. Дополнительные сведения см. в разделе «Создание таблиц отслеживания для метаданных на уровне области».

Обновление или удаление с удаленного узла применяется к базовой таблице.

scope_update_peer_key

Идентификатор узла, выполнившего последнее обновление или удаление.

Обновление или удаление с удаленного узла применяется к базовой таблице.

scope_update_peer_timestamp

Значение отметки времени в удаленной базе данных в момент первоначального обновления или удаления строки.

Обновление или удаление с удаленного узла применяется к базовой таблице.

local_update_peer_key

Идентификатор локального узла. Данный столбец будет содержать значение 0 для каждой строки, если локальная база данных не была восстановлена из резервной копии. 1

Обновление или удаление, выполненное в локальной операции или на удаленном узле, применяется к базовой таблице.

local_update_peer_timestamp

Значение отметки времени в локальной базе данных в момент обновления или удаления строки в локальной базе данных. 1

Обновление или удаление, выполненное в локальной операции или на удаленном узле, применяется к базовой таблице.

create_scope_local_id

Идентификатор области, выполнившей вставку. Для обновлений или удалений, выполняемых на локальном узле, значение данного столбца равно NULL.

Относится к столбцу scope_local_id в таблице сведений области. Дополнительные сведения см. в подразделе «Создание таблиц отслеживания для метаданных на уровне области» раздела Как подготовить серверную базу данных для синхронизации совместной работы (не SQL Server).

Вставка, выполненная на удаленном узле, применяется к базовой таблице.

scope_create_peer_key

Идентификатор узла, выполнившего вставку.

Вставка, выполненная на удаленном узле, применяется к базовой таблице.

scope_create_peer_timestamp

Значение отметки времени в удаленной базе данных в момент первоначальной вставки строки.

Вставка, выполненная на удаленном узле, применяется к базовой таблице.

local_create_peer_key

Идентификатор локального узла. Данный столбец будет содержать значение 0 для каждой строки, если локальная база данных не была восстановлена из резервной копии. 1

Вставка, выполненная в локальной операции или на удаленном узле, применяется к базовой таблице.

local_create_peer_timestamp

Значение отметки времени в локальной базе данных в момент вставки строки в локальную базу данных. 1

Вставка, выполненная в локальной операции или на удаленном узле, применяется к базовой таблице.

sync_row_is_tombstone

Значение 1 указывает на запись метаданных для удаления в базовой таблице.

Строка удаляется из базовой таблицы. Удаление может происходить с локального или удаленного узла.

last_change_datetime

Дата и время последнего обновления строки метаданных.

Строка вставляется или обновляется в этой таблице отслеживания.

restore_timestamp

Хранит значение local_update_peer_timestamp на время восстановления базы данных. Затем это значение используется в качестве значения отметки времени локального обновления.

Обычно имеет значение NULL, но может устанавливаться процессом восстановления. При каждом обновлении строки устанавливается в значение NULL.

<Столбцы фильтра> — добавьте столбец для каждого столбца, не входящего в первичный ключ и используемого в фильтрующем предложении WHERE для любой области.

Требуется только в случае, если таблица фильтруется для одной или нескольких областей. Хранит значение фильтруемых столбцов для операций вставки, обновления и удаления.

Строка вставляется, обновляется или удаляется из базовой таблицы. Удаление может происходить с локального или удаленного узла.

1 Используется Sync Framework при синхронизации перекрывающихся областей. Рассмотрим следующий пример обновления для базы данных, которая синхронизирует область X с клиентом А и область Y с клиентом Б. Обе области содержат строку Q.

  1. Строка Q обновляется на клиенте А и затем синхронизируется с базой данных.

  2. Клиент Б синхронизируется с базой данных и получает обновление для строки Q.

    Клиенту Б недоступна область X, и поэтому изменение с клиента А должно выглядеть как совершенное в базе данных. Для этого значения из local_update_peer_key и local_update_peer_timestamp используются при синхронизации с клиентом Б или любым другим клиентом, который не синхронизирует область, хранящуюся в update_scope_local_id для строки Q.

  3. Строка Q обновляется в базе данных, а затем синхронизируется с клиентом А.

    Клиенту А доступна область X, поэтому значения из scope_update_peer_key и scope_update_peer_timestamp используются для синхронизации с клиентом А или любым другим клиентом, который синхронизирует область X.

Рекомендуется создать отдельную схему базы данных для таблицы отслеживания и всех прочих объектов, связанных с метаданными синхронизации. Это помогает изолировать метаданные от данных в базовых таблицах. Для достижения оптимальной производительности создайте индексы в каждой таблице отслеживания.

  • Если данные не фильтруются, используйте тот же первичный ключ, что и в базовой таблице, и создайте некластеризованный индекс на (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_Tracking при обновлении таблицы Sales.Customer. Примеры триггеров Delete и Insert см. в разделе Инструкции по сценариям установки для поставщика базы данных.

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

Создание таблиц отслеживания для метаданных на уровне области

Метаданные уровня области обычно отслеживаются с помощью двух таблиц в каждой базе данных.

  • База данных сведений области сохраняет набор знаний синхронизации в двоичном формате для каждой области. Областью называется логическое группирование таблиц, определяющее, какие данные должны синхронизироваться как единое целое.

  • В таблице сопоставления областей показано, какие таблицы из базы данных принадлежат той или иной области. Таблица может принадлежать нескольким областям сразу. Таблица сопоставления должна содержать одну запись для каждой пары <область, таблица>.

Sync Framework использует набор знаний для определения изменений, отправляемых в каждую базу данных в ходе синхронизации. Приложению не обязательно напрямую работать со знаниями. Рассмотрим топологию двунаправленной синхронизации с тремя узлами.

  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)

Определение областей для синхронизации

После создания таблиц области определите одну или несколько областей для синхронизации. Например, можно определить область с именем Sales и включить в нее таблицы Customer, CustomerContact, OrderHeader и OrderDetail. Во время синхронизации области Sales два узла обмениваются изменениями, внесенными в эти четыре таблицы. Процесс определения области состоит из двух частей.

  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. Укажите имя области в свойстве ScopeName объекта DbSyncProvider и добавьте объект DbSyncAdapter для каждой таблицы, которую нужно включить в область. Дополнительные сведения см. в подразделе «Код приложения для имени области и соединения» раздела Как настроить и выполнить синхронизацию совместной работы (не SQL Server).

Важное примечаниеВажно!

После первой синхронизации области данную область нельзя изменять. Изменение таблиц в области или фильтрация предложений для этих таблиц может привести к расхождению данных.

Отфильтрованные и перекрывающиеся области

Область называется отфильтрованной, если в нее входит только часть строк из базовой таблицы. Например, можно определить отфильтрованную область с именем sales-WA, содержащую данные о продажах в штате Вашингтон. Чтобы отфильтровать данные, в запрос или процедуру, задаваемые в свойстве SelectIncrementalChangesCommand объекта DbSyncAdapter, необходимо включить предложение WHERE, которое выбирает соответствующие данные. При выполнении запроса или процедуры должны выбраться изменения на основе столбцов фильтров в таблице отслеживания, а не столбцов фильтров в базовой таблице.

Следующие типы фильтрации не поддерживаются.

  • Фильтрация столбцов: в запросы или процедуры, которые выбирают и применяют изменения, необходимо включать все столбцы.

  • Обновления столбцов, используемых для фильтрации: если пользователь обновляет значение в столбце, используемом для фильтрации, то строка перемещается из одной области в другую. Строка передается в новую область, в которой она должна находиться, при этом строка не удаляется из прежней области.

Области перекрывают друг друга, если они содержат одинаковые данные. Например, таблица products могла бы быть включена в область sales и в область inventory. Области могут как перекрываться, так и быть отфильтрованными. Следующие сценарии демонстрируют случаи, когда могут происходить фильтрация и перекрывание:

  • Сценарий 1.

    • Область 1 — sales-WA. В эту область входит products; orders с фильтром state=WA и order_details с фильтром state=WA.

    • Область 2 — sales-OR. В эту область входит products; orders с фильтром state=OR и order_details с фильтром state=OR.

    В данном сценарии вся таблица products является общей для обеих областей. Таблицы orders и order_details находятся в обеих областях, но фильтры не перекрывают друг друга, поэтому области не имеют одинаковых строк для этих таблиц.

  • Сценарий 2.

    • Область 1 — sales-WA. В эту область входит products; orders с фильтром state=WA и order_details с фильтром state=WA.

    • Область 2 — sales-Northwest. В эту область входит products; orders с фильтром state=WA OR state=ID и shippers.

    В данном сценарии вся таблица products снова является общей для обеих областей. Таблица orders входит в обе области, и фильтры перекрываются: обе области содержат строки, которые проходят фильтр state=WA. Таблицы shippers и order_details не являются общими для двух областей.

Области можно определять большим числом различных способов, однако необходимо придерживаться следующего правила: любые данные, синхронизируемые между парой баз данных в топологии синхронизации, могут принадлежать только одной области. Например, в приведенном выше сценарии 2 база данных А и база данных Б могут быть синхронизированы с областью 1; а база данных А и база данных В — с областью 2. База данных A и база данных Б не могут быть синхронизированы с областью 2, поскольку строки products и orders относятся к обеим областям.

Создание хранимых процедур для выбора и обновления данных и метаданных

После создания таблиц метаданных создайте SQL-запросы или хранимые процедуры (рекомендуется) для выбора и применения изменений в базовых таблицах и таблицах метаданных. По соображениям производительности и безопасности рекомендуется использовать хранимые процедуры. Такие запросы или процедуры указываются для следующих команд DbSyncAdapter. Эти команды описаны в подразделе «Адаптер синхронизации» раздела Как настроить и выполнить синхронизацию совместной работы (не SQL Server).

Следующие примеры кода создают набор хранимых процедур для обработки изменений данных и метаданных для таблицы Sales.Customer. Для краткости сюда включены процедуры выборки данных обработки обновлений и не включены процедуры вставки и удаления. Примеры хранимых процедур вставки и удаления см. в разделе Инструкции по сценариям установки для поставщика базы данных. Шаблон, который позволяет упростить создание всех этих хранимых процедур, представлен в разделе Шаблон провизионирования сервера (не SQL Server).

В полном примере кода в конце раздела многие значения, которые передаются этим хранимым процедурам, взяты из переменных сеанса. Переменные сеанса являются встроенными переменными, позволяющими службам Sync Framework передавать значения командам во время сеанса синхронизации. Дополнительные сведения о переменных сеанса см. в разделе Как использовать переменные сеанса для синхронизации совместной работы (не SQL Server).

Процедура для 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_CustomerContact_UpdateMetadata (
        @CustomerId uniqueidentifier,
        @PhoneType nvarchar(100),
        @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.CustomerContact_Tracking 
    where CustomerId = @CustomerId and PhoneType = @PhoneType
    
    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.CustomerContact_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 PhoneType = @PhoneType   
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    else    
        update Sync.CustomerContact_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 PhoneType = @PhoneType 
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    set @sync_row_count = @@rowcount

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)