Synchronizacja pomiędzy instancjami SQL za pomocą Sync Framework

W tym poradniku przedstawiamy w jak prosty sposób otrzymujemy możliwość, aby zsynchronizować dane pomiędzy dwoma instancjami MS SQL Server.

Co będzie nam potrzebne?

Do zastosowania tego poradnika będziemy potrzebować:

  1. Visual Studio
  2. Sync Framework – do pobrania:
    SDK – https://www.microsoft.com/en-us/download/details.aspx?id=23217
    Redist – https://www.microsoft.com/en-us/download/details.aspx?id=19502
  3. Dwóch instancji MS SQL – najlepiej jednej „master”, czyli pełnej ze wszystkimi zmianami i drugiej „slave” – czyli tej, do której będziemy kopiować dane.

A więc całość rozpoczynamy od dodania odpowiednich referencji w naszym projekcie.

using Microsoft.Synchronization;

using Microsoft.Synchronization.Data;

using Microsoft.Synchronization.Data.SqlServer;

using System.Data.SqlClient;

Listing 1. Refrerencje potrzebne do działania synchronizacji.

Następnie przechodzimy do części praktycznej. Całość nie jest bardzo skomplikowana, ale wymaga skupienia się na tym, co robimy, bo nawet mały, drobny błąd może nas (i naszą bazę) sporo kosztować.

Rozpoczynamy od zadeklarowania paru zmiennych, które uproszczą nam sporo pracę w późniejszych krokach.

SyncOrchestrator agent = new SyncOrchestrator(); // Główny obiekt synchronizatora

const string scopeName = “DowolnaNazwa”; // Nazwa zakresu naszej synchronizacji, mamy tu pełną dowolność
SqlConnection sqlConnSlave = new SqlConnection(@”Connection String Bazy slave”);

SqlConnection sqlConnMaster = new SqlConnection(@”Connection String Bazy master”);

SqlSyncProvider sqlProviderSlave = new SqlSyncProvider(scopeName, sqlConnSlave);

SqlSyncProvider sqlProviderMaster = new SqlSyncProvider(scopeName, sqlConnMaster);

SqlSyncScopeProvisioning scopeProvisionMaster = new SqlSyncScopeProvisioning(sqlConnMaster);

Listing 2. Dodatkowe zmienne, przydatne w dalszych krokach.

Jako iż same connection stringi możemy tworzyć na 2 lub nawet 3 (jeżeli policzymy też ręczne jego wprowadzenie) różne sposoby, wybierz ten, który najbardziej Ci odpowiada.

Teraz przejdźmy do miejsca, w którym ostatecznie przeprowadzimy naszą synchronizację.

if (!scopeProvisionMaster.ScopeExists(scopeName)) // Sprawdzamy, czy nasz zakres istnieje na serwerze master, jezeli nie, to go tworzymy, dodajac odpowiednie tabele, ktore chcemy synchronizowac

{

DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(scopeName);

scopeDesc.Tables.Clear();

scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Nazwa tabeli 1", sqlConnMaster));

scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Nazwa tabeli 2", sqlConnMaster));

scopeProvisionLocal.PopulateFromScopeDescription(scopeDesc);

scopeProvisionLocal.SetCreateTableDefault(DbSyncCreationOption.CreateOrUseExisting);

scopeProvisionLocal.Apply();

}

Listing 3. Kod przygotowywujący bazę master do synchronizacji.

Teraz powtarzamy tą samą operację dla bazy slave, ale nie dodajemy tu tabel, ponieważ jeszcze ich tam nie ma, chcemy dopiero je utworzyć. Kod więc będzie wyglądał podobnie do tego:

SqlSyncScopeProvisioning scopeProvisionSlave = new SqlSyncScopeProvisioning(sqlConnSlave);

if (!scopeProvisionRemote.ScopeExists(scopeName))

{

DbSyncScopeDescription scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope(scopeName, sqlConnMaster);

scopeProvisionRemote.PopulateFromScopeDescription(scopeDesc);

scopeProvisionRemote.Apply();

}

Listing 4. Kod przygotowywujący bazę slave do synchronizacji.

Teraz pozostaje nam tylko dodać kod uruchamiający cały proces synchronizacji. Niestety nie mamy możliwości zrobienia tego asynchronicznie, więc jeżeli chcemy, aby proces synchronizacji nie zawieszał naszej aplikacji, musimy zrobić to w całkowicie oddzielnym wątku.

agent.LocalProvider = sqlProviderLocal;

agent.RemoteProvider = sqlProviderRemote;

SyncOperationStatistics stats = agent.Synchronize(); // Uruchamiamy synchronizację i zapisujemy statystyki do obiektu.

Listing 5. Kod uruchamiający synchronizację.

Po zakończeniu synchronizacji możemy skorzystać z naszego obiektu „stats”, w którym przechowywane będą informacje na temat przeprowadzonego procesu takie jak ilość wysłanych/pobranych danych, ile zmian zastosowano, ile zakończono z błędem, czas rozpoczęcia i zakończenia synchronizacji.