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

2009年12月3日木曜日

Sync Frameworkによるファイルの同期

いろいろあってSync Frameworkによる同期について調査。
とりあえず、でやってみたのは「ファイルの同期」。SyncToyとか使ってやればいいんだけど勉強と調査をかねてやってみた。

結論から言うと「物凄く簡単にファイル同期ができる」というところに。

注意すべきところは
「参照設定で個別にSyncFrameworkのDllを設定する必要がある」
点かな。今回のファイル同期であれば、

  • Microsoft.Synchronization(Microsoft.Synchronization.dll)
  • Microsoft.Synchronization.Files(Microsoft.Synchronization.Files.dll)

これらはSyncFramework2.0をインストールすると、ProgramFiles関係のフォルダにインストールされているのでそこから直接参照しないといけないのよ。GACに入っていると思っていたから少し探してしまった。

'同期オプションの指定

Dim syncOption As FileSyncOptions = FileSyncOptions.CompareFileStreams Or FileSyncOptions.ExplicitDetectChanges Or FileSyncOptions.RecycleConflictLoserFiles Or FileSyncOptions.RecycleDeletedFiles

 

'対象ファイルの設定(今回未使用)
Dim syncFilter As New FileSyncScopeFilter
With syncFilter

End With

 

'同期処理の実行
Using src As New FileSyncProvider(コピー元, Nothing, syncOption)
    Using dest As New FileSyncProvider(コピー先, Nothing, syncOption)

        src.DetectChanges()
        dest.DetectChanges()

        Dim syncAgent As New SyncOrchestrator
        With syncAgent
            .RemoteProvider = src
            .LocalProvider = dest
            .Direction = SyncDirectionOrder.Download
            .Synchronize()
        End With

    End Using
End Using

 

以上がファイル同期に書いてみたソースの全部。これだけで楽々できてしまうので、業務システムとかでよくある最新モジュールの適用などは大分楽にできるようになるねぇ。もちろんセキュリティ関係とか処理タイミングとか考えないといけないことが多々あるので、そこらへんは一工夫。