2009年12月7日月曜日

Sync FrameworkによるDBの同期

前回がファイル・フォルダの同期だったので今回はデータベースの同期にチャレンジ。ただ、やろうと思うと結構難しいところがでてくる(異種DBとか)ので、今回はダンプファイルからリストアよろしく、親DBの内容を子DBに単純コピーする程度でやってみた。

ちと長めになるけどこんなソース。

Private Sub DbSync()

    Const SCOPE_NAME As String = "SCOPE1"
    Const SCHEMA_NAME As String = "" '"Sync"
    Const PREFIX_NAME As String = "Sync"

    Dim sourceProvider As New SqlSyncProvider
    Dim destinationProvider As New SqlSyncProvider

    Dim srcStr As New SqlConnectionStringBuilder
    Dim desStr As New SqlConnectionStringBuilder
    With srcStr
        .DataSource = "TESTSERVER"
        .InitialCatalog = "TESTDB"
        .PersistSecurityInfo = True
        .IntegratedSecurity = True
    End With
    With
desStr
        .DataSource = "TESTSERVER"
        .InitialCatalog = "TESTDB2"
        .PersistSecurityInfo = True
        .IntegratedSecurity = True
    End With

    Using srcConn As New SqlConnection(srcStr.ToString)
        Using desConn As New SqlConnection(desStr.ToString)
           '変更追跡用テーブルを生成
            Dim serverScope As New DbSyncScopeDescription(SCOPE_NAME)
            '対象テーブル一覧の取得
            Dim query As String = "SELECT NAME, OBJECT_ID FROM SYS.TABLES"
            Using sqlAdapter As New SqlDataAdapter(query, srcConn)
                Using tblSet As New DataTable
                    sqlAdapter.Fill(tblSet)
                    For Each child As DataRow In tblSet.Rows
                        If child.Item(0).ToString.Contains(PREFIX_NAME) Then Continue For

                        Dim targetTable As DbSyncTableDescription = _
                          SqlSyncDescriptionBuilder.GetDescriptionForTable(child.Item(0).ToString, srcConn)
                        serverScope.Tables.Add(targetTable)
                    Next
                End Using
            End Using

            ‘同期の設定

            Dim serverConfig As New SqlSyncScopeProvisioning(serverScope)
            With serverConfig
                .ObjectSchema = SCHEMA_NAME
                .ObjectPrefix = PREFIX_NAME

                If Not .ScopeExists(SCOPE_NAME, srcConn) Then
                    .SetCreateTableDefault(DbSyncCreationOption.Skip)
                    .Apply(srcConn)
                End If

            End With

            Dim clientScope As DbSyncScopeDescription = _
                SqlSyncDescriptionBuilder.GetDescriptionForScope(SCOPE_NAME, PREFIX_NAME, SCHEMA_NAME, srcConn)
            Dim clientConfig As New SqlSyncScopeProvisioning(clientScope)
            With clientConfig
                .ObjectSchema = SCHEMA_NAME
                .ObjectPrefix = PREFIX_NAME

                If Not .ScopeExists(SCOPE_NAME, desConn) Then
                    .Apply(desConn)
                End If
            End With

            With sourceProvider
                .ScopeName = SCOPE_NAME
                .ObjectPrefix = PREFIX_NAME
                .ObjectSchema = SCHEMA_NAME
                .Connection = srcConn
            End With
            With
destinationProvider
                .ScopeName = SCOPE_NAME
                .Connection = desConn
                .ObjectPrefix = PREFIX_NAME
                .ObjectSchema = SCHEMA_NAME
            End With 
           
‘同期処理の実行
            Dim syncAgent As New SyncOrchestrator
            With syncAgent
                .RemoteProvider = sourceProvider
                .LocalProvider = destinationProvider
                .Direction = SyncDirectionOrder.Download
                .Synchronize()
            End With

        End Using

    End Using

 

    MessageBox.Show("DBの同期が終了しました。", My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Information)

End Sub

とりあえずこのくらいのロジックで、DB間にてレコードの同期を取ることができた。

気を付けるのは、レコード間の同期を取るために専用のテーブルやトリガ、ストアドプロシージャが必要になるんだけど、それはSqlSyncScopeProvisioning.Applyメソッド呼び出し時に作成してくれる。この時このサンプルのようにスキーマを設定していないと、同一スキーマに作成される=同一権限の人にはテーブルやらがたくさん増えて見える、ことになるのが注意。スキーマを予め用意しておけば、切り離して見ることができるのでそれがベター、というかベストだろうねぇ。

残念ながらスキーマまでは作成してくれませんw

0 件のコメント:

コメントを投稿