注意古いクライアントによってプロビジョニングされた列またはテーブルを削除すると、私が持っている解決策は機能しません。列を削除する場合は、複数のフェーズを実行する必要があります。最初に全員をバージョン 1 にアップグレードします。すべてのクライアントがアップグレードされたら、列とテーブルを削除できます。
考えられる解決策
私があなたをよく理解していれば、複数のプロビジョニングされた構成を持つ 1 つのスコープまたはテンプレートが必要です。
あなたのスコープ:
- (バージョン1)
- (バージョン2)
- Table1(ColumnA、ColumnB、NewColumnC )
- NewTable2(ColumnX、ColumnY、ColumnZ)
私の意見では、使用する方が良いです:
Version1_YourScope:
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
ステートメントが含まれていることに注意してください。GO
1 つの 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のみをプロビジョニングして、クライアント側が複数のバージョン間で重複しないようにします。
フィルター パラメーターを渡すためにテンプレートを使用している場合は、次の点に注意する必要があります。
- 複数のスコープで言及されているテーブルの異なるフィルター処理された列は、トリガーが複数のフィルター処理された列を使用する複数のスコープを認識しないため、問題を引き起こします
- 新しいフィルター処理された列をプロビジョニングするには、既存の追跡テーブルに新しい列が必要です
幸運を!