如何将参数传递给 Microsoft Sync 2.1 生成的存储过程

Posted

技术标签:

【中文标题】如何将参数传递给 Microsoft Sync 2.1 生成的存储过程【英文标题】:How to pass parameter to Microsoft Sync 2.1 generated Stored procedures 【发布时间】:2013-05-24 15:32:26 【问题描述】:

我使用的是微软同步框架 2.1 版本

我们正在尝试实现数据库版本控制,即如果服务器数据库中的表架构发生更改,所有或部分客户端应该仍然能够同步他们的数据,而无需进行相同的架构更改或更新数据库。 在更高级别上,我们需要为具有相同服务器数据库的不同客户端维护多个应用程序版本。

我正在尝试将应用程序版本作为参数传递给所有存储过程,以便我可以处理多个客户端的数据版本。 我可以将参数传递给“select_chagnes”存储过程..但是我的问题是如何将版本号传递给所有同步生成的存储过程,以便在所有同步生成的过程中生成参数@version .

欢迎任何维护客户特定数据的建议我们的主要目标是允许现有客户同步他们的数据库而无需进行最新的数据库更改。这样我们就可以让客户端拥有多个指向同一个服务器数据库的应用程序版本。

【问题讨论】:

额外参数在其他同步存储过程中会做什么?如果您不手动更改那些存储的过程,那么您的额外参数无效。 @JuneT 我想在所有存储过程中使用额外的参数来识别客户端并维护客户端特定版本的数据库。示例:如果在新版本的数据库中发生架构更改,并且客户端应该能够在不更改架构的情况下使用应用程序。在将数据插入表中时,将使用额外参数识别客户端版本,并将插入相关架构更改的默认值。 .. 架构更改不会自动反映在 Sync Framework 范围内。如果您不删除范围中使用的列,或者您不添加不允许空值的列,则同步应该没问题。要回答您的问题,API 中没有任何内容允许您向写入操作添加和传递参数。 【参考方案1】:

备注如果您删除旧客户提供的列或表,我的解决方案将不起作用。如果要删除列,则需要执行多个阶段。首先将所有人升级到版本 1。如果所有客户端都升级了,您可以删除列和表。

可能的解决方案

如果我理解你的话,你希望一个范围或模板具有多个预置配置。

你的范围:

(版本 1) 表 1(A 列,B 列) (版本 2) Table1(ColumnA, ColumnB, NewColumnC) NewTable2(ColumnX, ColumnY, ColumnZ)

我认为最好使用:

Version1_YourScope:

表 1(A 列,B 列)

Version2_YourScope:

Table1(ColumnA, ColumnB, NewColumnC) 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 语句。您需要在一个 SqlCommand 中执行两个 GO 之间的所有内容。

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,这样客户端就不会在多个版本之间重叠。

如果您因为要传递过滤器参数而使用模板,则需要注意以下事项:

在多个范围中提到的表的不同过滤列会导致问题,因为触发器不知道使用多个过滤列的多个范围 提供一个新的过滤列需要一个新列到一个已经存在的跟踪表中

祝你好运!

【讨论】:

以上是关于如何将参数传递给 Microsoft Sync 2.1 生成的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

Microsoft Access VBA 将参数传递给报表

使用 Microsoft.Toolkit.Mvvm 和 Microsoft.Xaml.Behaviors.Wpf 将事件参数传递给命令

如何将多个参数传递给 ASP.NET CORE MVC 中的 HttpGet 方法?

Angular 2:如何将路由参数传递给子路由?

如何将参数传递给 erlang os:cmd()?

调用如何将其参数传递给内部函数? [复制]