7

Microsoft 同期フレームワーク 2.1 バージョンを使用しています

データベースのバージョン管理を実装しようとしています。つまり、サーバー データベースにテーブル スキーマの変更がある場合、すべてまたは一部のクライアントは、同じスキーマの変更を行わずに、または更新された DB を使用せずにデータを同期できる必要があります。上位レベルでは、同じサーバー DB を持つさまざまなクライアントに対して複数のアプリケーション バージョンを維持する必要があります。

複数のクライアントのデータ バージョンを処理できるように、アプリケーション バージョンをパラメーターとしてすべてのストアド プロシージャに渡そうとしています。パラメータを「select_chagnes」ストアドプロシージャに渡すことができます..しかし、私の質問は、同期によって生成されたすべてのストアドプロシージャにバージョン番号を渡して、同期によって生成されたすべてのプロシージャでパラメータ @version が生成されるようにする方法です。

また

クライアント固有のデータを維持するための提案は大歓迎です。私たちの主な目標は、既存のクライアントが最新のデータベース変更を行わずにデータベースを同期できるようにすることです。クライアントが同じサーバーデータベースを指す複数のアプリケーションバージョンを持つことができるようにします。

4

1 に答える 1

4

注意古いクライアントによってプロビジョニングされた列またはテーブルを削除すると、私が持っている解決策は機能しません。列を削除する場合は、複数のフェーズを実行する必要があります。最初に全員をバージョン 1 にアップグレードします。すべてのクライアントがアップグレードされたら、列とテーブルを削除できます。

考えられる解決策

私があなたをよく理解していれば、複数のプロビジョニングされた構成を持つ 1 つのスコープまたはテンプレートが必要です。

あなたのスコープ:

  • (バージョン1)
    • Table1(列A、列B)
  • (バージョン2)
    • Table1(ColumnA、ColumnB、NewColumnC )
    • NewTable2(ColumnX、ColumnY、ColumnZ)

私の意見では、使用する方が良いです:

Version1_YourScope:

  • Table1(列A、列B)

Version2_YourScope:

  • Table1(ColumnA、ColumnB、NewColumnC )
  • NewTable2(ColumnX Columny ColumnZ)

したがって、この場合、Sync Framework プロシージャでバージョンを処理する必要はありません。今度は、適切なクライアントに適切なスコープ セットを与えることによって、外部でバージョンを処理する必要があります。

何をすべきか:

この変更には、プロビジョニング中にいくつかの変更が必要です。スコープを互いにオーバーラップさせると、いくつかの問題が発生します。

  • Table1 には 2 つの BulkTypes が必要です (1 つは NewColumnC なし、もう1 つはこの新しい列を内部に含むタイプ)。
  • Table1 には 2 つの選択変更が必要です
  • Table1 には 2 つの BulkInsert sp が必要です
  • Table1 のトリガーのセットを 1 つだけにしたい場合
  • Table1 の追跡テーブルを 1 つだけにしたい
  • ...

プロビジョニング中は、おそらくSqlSyncScopeProvider.Apply(). スクリプトを適用する代わりにスクリプトを返す関数もあります: SqlSyncScopeProvider.Script(). これにより、プロビジョニング スクリプトが返されます。

したがって、次のようなことができます。

1: 次のプロビジョニング設定を使用して、スコープの重複を可能にします。

_scopeProvisioning.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create);
_scopeProvisioning.SetCreateTableDefault(DbSyncCreationOption.Skip);
_scopeProvisioning.SetCreateProceduresDefault(DbSyncCreationOption.CreateOrUseExisting);
_scopeProvisioning.SetCreateTrackingTableDefault(DbSyncCreationOption.CreateOrUseExisting);
_scopeProvisioning.SetCreateTriggersDefault(DbSyncCreationOption.CreateOrUseExisting);

2: プロビジョニング スクリプトを取得する

var builder = new StringBuilder(_scopeProvisioning.Script());

3: 各テーブルの名前<tablename>_<procedure/bulktype><scopename>_<tablename>_<procedure/bulktype>

// Rename <tablename>_selectchanges to <scopename>_<tablename>_selectchanges and also all other stored procedures and bulk type
builder = builder.Replace(String.Format("CREATE PROCEDURE [{0}_selectchanges", table.Name), String.Format("CREATE PROCEDURE [sync].[{1}_{0}_selectchanges", table.Name, scope.Name));
builder = builder.Replace(String.Format("SelChngProc=\"[{0}_selectchanges", table.Name), String.Format("SelChngProc=\"[sync].[{1}_{0}_selectchanges", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_BulkType]", table.Name), String.Format("[{1}_{0}_BulkType]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_selectrow]", table.Name), String.Format("[{1}_{0}_selectrow]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_insert]", table.Name), String.Format("[{1}_{0}_insert]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_update]", table.Name), String.Format("[{1}_{0}_update]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_delete]", table.Name), String.Format("[{1}_{0}_delete]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_insertmetadata]", table.Name), String.Format("[{1}_{0}_insertmetadata]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_updatemetadata]", table.Name), String.Format("[{1}_{0}_updatemetadata]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_deletemetadata]", table.Name), String.Format("[{1}_{0}_deletemetadata]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_bulkinsert]", table.Name), String.Format("[{1}_{0}_bulkinsert]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_bulkupdate]", table.Name), String.Format("[{1}_{0}_bulkupdate]", table.Name, scope.Name));
builder = builder.Replace(String.Format("[{0}_bulkdelete]", table.Name), String.Format("[{1}_{0}_bulkdelete]", table.Name, scope.Name));

4: 既存のスコープと重複する各テーブルについて、データベースに既に存在するため、CREATE TRIGGER を ALTER TRIGGER に変更します。

builder = builder.Replace(String.Format("CREATE TRIGGER [{0}_insert_trigger]", table.Name), String.Format("ALTER TRIGGER [{0}_insert_trigger]", table.Name));
builder = builder.Replace(String.Format("CREATE TRIGGER [{0}_update_trigger]", table.Name), String.Format("ALTER TRIGGER [{0}_update_trigger]", table.Name));
builder = builder.Replace(String.Format("CREATE TRIGGER [{0}_delete_trigger]", table.Name), String.Format("ALTER TRIGGER [{0}_delete_trigger]", table.Name));

5: 新しいスクリプトを実行します。スクリプトには多くのGOステートメントが含まれていることに注意してください。GO1 つの SqlCommand で2 つの の間のすべてを実行する必要があります。

string[] seperatedScript = GetProvisionScriptSplittedOnGOstatement(builder.ToString);
foreach(string command in seperatedScript)
{
   new SqlCommand(command, connection).ExecuteNonQuery(); 
  // make sure you dispose SqlCommand correctly. Not in this example
}

6: 古いクライアントはVersion1_YourScope のみをプロビジョニングし、新しいクライアントはVersion2_YourScopeのみをプロビジョニングして、クライアント側が複数のバージョン間で重複しないようにします。

フィルター パラメーターを渡すためにテンプレートを使用している場合は、次の点に注意する必要があります。

  • 複数のスコープで言及されているテーブルの異なるフィルター処理された列は、トリガーが複数のフィルター処理された列を使用する複数のスコープを認識しないため、問題を引き起こします
  • 新しいフィルター処理された列をプロビジョニングするには、既存の追跡テーブルに新しい列が必要です

幸運を!

于 2013-06-04T13:49:27.857 に答える