备注如果您删除旧客户端提供的列或表,我的解决方案将不起作用。如果要删除列,则需要执行多个阶段。首先将每个人升级到版本 1。如果所有客户端都升级了,您可以删除列和表。
可能的解决方案
如果我很好理解您,您希望一个范围或模板具有多个预置配置。
你的范围:
- (版本1)
- (版本2)
- 表 1(A 列、B 列、C 列)
- 新表 2(列 X、列 Y、列 Z)
在我看来,最好使用:
版本 1_YourScope:
版本 2_YourScope:
- 表 1(A 列、B 列、C 列)
- NewTable2(ColumnX Columny ColumnZ)
因此,在这种情况下,您不必处理 Sync Framework 过程中的版本,现在您需要通过为正确的客户端提供正确的范围集来处理外部版本。
该怎么办:
此更改需要在配置期间进行一些更改。范围相互重叠会带来一些问题:
- 您必须有两个用于 Table1 的 BulkType(1 个没有NewColumnC,1 个类型包含这个新列)
- 您必须对 Table1 进行两个选择更改
- Table1 必须有两个 BulkInsert sp
- 您只想为 Table1 设置一组触发器
- 您只想为 Table1 提供一个跟踪表
- ...
在配置期间,您可能会使用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
在一个 SqlCommand 中执行两个之间的所有内容。
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,因此客户端多个版本之间没有重叠。
如果您因为要传递过滤器参数而使用模板,则需要注意以下事项:
- 在多个范围中提到的表的不同过滤列会导致问题,因为触发器不知道使用多个过滤列的多个范围
- 供应一个新的过滤列需要一个新列到一个已经存在的跟踪表
祝你好运!