您的位置:首页 > 其它

微软同步框架入门之三--分析生成的同步类文件

2008-11-19 18:02 429 查看
在前两篇文章当中,我介绍了SnapShot(快照方式)和“只同步新更改和增量更改”这两种同步方

式。将使用设计器同步向导生成了两个相应的DEMO。今天我们会一起分析一下这两个DEMO中相应的同

步文件内容和相互差异(DEMO下载,请点击这里)。

首先要分析的DEMO是“只同步新更改和增量更改”,我们用VS2008打开DEMO的解决方案方案,如

下图:

//之前是添回和删除SQL对象的设置

// dnt_posts1SyncTableUpdateCommand command.

this.UpdateCommand = new System.Data.SqlClient.SqlCommand();

this.UpdateCommand.CommandText = @"UPDATE dbo.dnt_posts1 SET [fid] = @fid, [tid] = @tid,

[parentid] = @parentid, [layer] = @layer, [poster] = @poster, [posterid] = @posterid,

[title] = @title, [postdatetime] = @postdatetime, [message] = @message, [ip] = @ip,

[lastedit] = @lastedit, [invisible] = @invisible, [usesig] = @usesig, [htmlon] = @htmlon,

[smileyoff] = @smileyoff, [parseurloff] = @parseurloff, [bbcodeoff] = @bbcodeoff,

[attachment] = @attachment, [rate] = @rate, [ratetimes] = @ratetimes, [LastEditDate] =

@LastEditDate, [CreationDate] = @CreationDate WHERE ([pid] = @pid) AND (@sync_force_write = 1

OR ([LastEditDate] <= @sync_last_received_anchor)) SET @sync_row_count = @@rowcount";

this.UpdateCommand.CommandType = System.Data.CommandType.Text;

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@fid", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@tid", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@parentid", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@layer", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@poster", System.Data.SqlDbType.NVarChar));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@posterid", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@title", System.Data.SqlDbType.NVarChar));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@postdatetime",

System.Data.SqlDbType.SmallDateTime));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@message", System.Data.SqlDbType.NText));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@ip", System.Data.SqlDbType.NVarChar));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@lastedit", System.Data.SqlDbType.NVarChar));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@invisible", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@usesig", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@htmlon", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@smileyoff", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@parseurloff", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@bbcodeoff", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@attachment", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@rate", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@ratetimes", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@LastEditDate", System.Data.SqlDbType.DateTime));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@CreationDate", System.Data.SqlDbType.DateTime));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@pid", System.Data.SqlDbType.Int));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@sync_force_write", System.Data.SqlDbType.Bit));

this.UpdateCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("@sync_last_received_anchor",

System.Data.SqlDbType.DateTime));

System.Data.SqlClient.SqlParameter updatecommand_sync_row_countParameter =

new System.Data.SqlClient.SqlParameter("@sync_row_count", System.Data.SqlDbType.Int);

updatecommand_sync_row_countParameter.Direction = System.Data.ParameterDirection.Output;

this.UpdateCommand.Parameters.Add(updatecommand_sync_row_countParameter);

}

上面代码首先是对命令(SqlCommand)实例的相关属性绑定,包括CommandText,CommandType, Parameters。

当然细心的朋友会发现,上面的UpdateCommand.CommandText绑定时在SQL命令行的后半部有如下内容(摘录):

[LastEditDate] = @LastEditDate, [CreationDate] = @CreationDate WHERE ([pid] = @pid)

AND (@sync_force_write = 1 OR ([LastEditDate] <= @sync_last_received_anchor))

SET @sync_row_count = @@rowcount";

其中我们看到是[LastEditDate],[CreationDate]这两个表字段实际上就是在上一篇文章中我们使用同步

向导进行设计时所做的相应设置如下:



而@sync_force_write参数与@sync_last_received_anchor参数则是Synchronization Services

供的一组会话变量中的两个,其中@sync_force_write会强制应用由于冲突或错误而未能应用的更改(强制写

入服务端数据库),而@sync_last_received_anchor则是将对在上次收到的定位点值(修改时间)之后和新

收到的定位点值(修改时间)之前所做的更改进行同步,说白了就是将最近一定修改的时间与当前修改发生的时

间进行同步,以便于本次只修改那些介于这两个时间点中间的数据即可。同时在完成本次同步时,将这个变量修

改为本次修改的时间(定位点),以便下次同步时做为新的时间依据(定位点)。

当然这种类型的变量的主要用场就是在同步期间通过它们将值传递给SyncAdapter 命令。这些变量的指定

方式与 ADO.NET 命令中查询或存储过程的其他参数相似(上面代码中已给出)。

当然Synchronization Services还提供了一些别的变量,这里为了大家开发方便,直接罗列一下了。

会话变量:sync_client_id、sync_client_id_hash 和 sync_originator_id

用法: 用于标识当前正在同步的客户端。ID 通常用于冲突检测,并防止在双向同步过程中将更改

发送回客户端。有关更多信息,请参见如何:在客户端和服务器间交换双向增量数据更改。

默认情况下,Synchronization Services 用 GUID 标识每个客户端,而 GUID 由 sync_client_id

返回。此外,还可以创建 ID 的散列值并在查询中使用 sync_client_id_hash;或者将 GUID 映射到一个

整数值并使用 sync_originator_id。

会话变量:sync_last_received_anchor, sync_new_received_anchor

用法: 用于定义在会话期间要同步的更改集。在当前同步期间,为 SelectNewAnchorCommand 属性

指定的命令提供一个新的定位点值。将对在上次收到的定位点值之后和新收到的定位点值之前所做的更

改进行同步。然后,存储新收到的定位点并在下一次同步时将其用作上一次收到的定位点值。

会话变量:sync_force_write

用法: 与 RetryWithForceWrite 的 ApplyAction 一起使用,强制应用由于冲突或错误而未能应用

的更改。

会话变量:sync_row_count

用法:返回服务器上受上一次操作影响的行数。在 SQL Server 数据库中,@@ROWCOUNT 提供此变量

的值。行数为 0 指示操作失败,通常是由于冲突或错误。

会话变量:sync_initialized

用法:返回一个值,指示当前同步是初始同步(值为 0)还是后续同步(值为 1)。

会话变量:sync_table_name 和sync_group_name

用法:当必须在查询中指定表名或组名时使用。

会话变量:sync_batch_count、sync_batch_size 和 sync_max_received_anchor

用法:当进行批量更改时使用。有关更多信息,请参见如何:指定更改的顺序和批大小。

会话变量:sync_session_id

用法:返回标识当前同步会话的 GUID 值。

看到这里,大家也就清楚了,所谓“只同步新更改和增量更改”只是在 CUD这类SQLCOMAND中加入

相应的判断条件即完成了相应的数据操作了,这的确要比“整表”同步(下面我们会看到)在效率速度上要

高多了。

当然,除了必要的CUD操作,同步设计器还会为我们生成一些其它的SQL命令,比如说:

SelectConflictDeletedRowsCommand: 获取或设置查询或存储过程,用于标识与其他更改相

冲突的已删除行。 在本DEMO中的部分设置如下:

this.SelectConflictDeletedRowsCommand = new System.Data.SqlClient.SqlCommand();

this.SelectConflictDeletedRowsCommand.CommandText = "";

this.SelectConflictDeletedRowsCommand.CommandType = System.Data.CommandType.Text;

this.SelectConflictDeletedRowsCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@pid", System.Data.SqlDbType.Int));

SelectConflictUpdatedRowsCommandl: 获取或设置查询或存储过程,用于标识与其他更改

相冲突的已更新行。在本DEMO中的部分设置如下:

this.SelectConflictUpdatedRowsCommand = new System.Data.SqlClient.SqlCommand();

this.SelectConflictUpdatedRowsCommand.CommandText = @"SELECT [pid], [fid], [tid], [parentid],

[layer], [poster], [posterid], [title], [postdatetime], [message], [ip], [lastedit],

[invisible], [usesig], [htmlon], [smileyoff], [parseurloff], [bbcodeoff], [attachment],

[rate], [ratetimes], [LastEditDate], [CreationDate] FROM dbo.dnt_posts1 WHERE ([pid] = @pid)";

this.SelectConflictUpdatedRowsCommand.CommandType = System.Data.CommandType.Text;

this.SelectConflictUpdatedRowsCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@pid", System.Data.SqlDbType.Int));

SelectIncrementalInsertsCommand: 获取或设置查询或存储过程,用于检索自上次同步之后

在服务器数据库中进行的插入。本DEMO中的部分设置如下:

this.SelectIncrementalInsertsCommand = new System.Data.SqlClient.SqlCommand();

this.SelectIncrementalInsertsCommand.CommandText = @"SELECT [pid], [fid], [tid], [parentid],

[layer], [poster], [posterid], [title], [postdatetime], [message], [ip], [lastedit],

[invisible], [usesig], [htmlon], [smileyoff], [parseurloff], [bbcodeoff], [attachment],

[rate], [ratetimes], [LastEditDate], [CreationDate] FROM dbo.dnt_posts1 WHERE ([CreationDate] >

@sync_last_received_anchor AND [CreationDate] <= @sync_new_received_anchor)";

this.SelectIncrementalInsertsCommand.CommandType = System.Data.CommandType.Text;

this.SelectIncrementalInsertsCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_last_received_anchor", System.Data.SqlDbType.DateTime));

this.SelectIncrementalInsertsCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_new_received_anchor", System.Data.SqlDbType.DateTime));

SelectIncrementalDeletesCommand: 获取或设置查询或存储过程,用于检索自上次同步之后

在服务器数据库中进行的删除。在本DEMO中的部分设置如下:

this.SelectIncrementalDeletesCommand = new System.Data.SqlClient.SqlCommand();

this.SelectIncrementalDeletesCommand.CommandText = "SELECT [pid], [DeletionDate] FROM

dbo.dnt_posts1_Tombstone WHERE (@sync_initializ" +

"ed = 1 AND [DeletionDate] > @sync_last_received_anchor AND [DeletionDate] <= @sy" +

"nc_new_received_anchor)";

this.SelectIncrementalDeletesCommand.CommandType = System.Data.CommandType.Text;

this.SelectIncrementalDeletesCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_initialized", System.Data.SqlDbType.Bit));

this.SelectIncrementalDeletesCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_last_received_anchor", System.Data.SqlDbType.DateTime));

this.SelectIncrementalDeletesCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_new_received_anchor", System.Data.SqlDbType.DateTime));

SelectIncrementalUpdatesCommand: 获取或设置查询或存储过程,用于检索自上次同步之后

在服务器数据库中进行的更新。在本DEMO中的部分设置如下:

this.SelectIncrementalUpdatesCommand = new System.Data.SqlClient.SqlCommand();

this.SelectIncrementalUpdatesCommand.CommandText = @"SELECT [pid], [fid], [tid], [parentid],

[layer], [poster], [posterid], [title], [postdatetime], [message], [ip], [lastedit], [invisible],

[usesig], [htmlon], [smileyoff], [parseurloff], [bbcodeoff], [attachment], [rate], [ratetimes],

[LastEditDate], [CreationDate] FROM dbo.dnt_posts1 WHERE ([LastEditDate] > @sync_last_received_anchor AND [LastEditDate] <= @sync_new_received_anchor AND [CreationDate] <= @sync_last_received_anchor)";

this.SelectIncrementalUpdatesCommand.CommandType = System.Data.CommandType.Text;

this.SelectIncrementalUpdatesCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_last_received_anchor", System.Data.SqlDbType.DateTime));

this.SelectIncrementalUpdatesCommand.Parameters.Add(

new System.Data.SqlClient.SqlParameter("@sync_new_received_anchor", System.Data.SqlDbType.DateTime));

因为语句很简单,这里不一一介绍了。更多信息大家可以查看SDK中的文档即可。

说到这里,关于dnt_posts1SyncAdapter这个服务器端的数据Adapter操作类就介绍的差不多了。

下面是BiDirectSyncDataServerSyncProvider类,其实这两个服务器端类的关系是一个封装引用关系,

因为BiDirectSyncDataServerSyncProvider类中提供了对dnt_posts1SyncAdapter的属性引用,所

以如果我们有对dnt_posts1SyncAdapter的访问操作,最好通过这个类进行访问。我们可以通过对该

类的构造方法来大致了解一下这个类的工作流程:

public BiDirectSyncDataServerSyncProvider() {

string connectionString = global::MSF_WinFormDemo.Properties.Settings.Default.ServertestConnectionString;

this.InitializeConnection(connectionString);

this.InitializeSyncAdapters();

this.InitializeNewAnchorCommand();

this.OnInitialized();

}

从代码中可以看到,其构造方法首先会调用config文件中的设置来初始化一个SQL链接如下:

this.Connection = new System.Data.SqlClient.SqlConnection(connectionString);

然后就是对相应的Adapter进行初始化了,代码如下:

[System.Diagnostics.DebuggerNonUserCodeAttribute()]

private void InitializeSyncAdapters() {

this._dnt_posts1SyncAdapter = new dnt_posts1SyncAdapter();

this.SyncAdapters.Add(this._dnt_posts1SyncAdapter);

}

紧接着就是对之前所说的Synchronization Services进行初始化:

[System.Diagnostics.DebuggerNonUserCodeAttribute()]

private void InitializeNewAnchorCommand() {

this.SelectNewAnchorCommand = new System.Data.SqlClient.SqlCommand();

this.SelectNewAnchorCommand.CommandText = "Select @sync_new_received_anchor = GETUTCDATE()";

this.SelectNewAnchorCommand.CommandType = System.Data.CommandType.Text;

System.Data.SqlClient.SqlParameter selectnewanchorcommand_sync_new_received_anchorParameter = new System.Data.SqlClient.SqlParameter("@sync_new_received_anchor", System.Data.SqlDbType.DateTime);

selectnewanchorcommand_sync_new_received_anchorParameter.Direction = System.Data.ParameterDirection.Output;

this.SelectNewAnchorCommand.Parameters.Add(selectnewanchorcommand_sync_new_received_anchorParameter);

}

这里要注意的是"Select @sync_new_received_anchor = GETUTCDATE()" 这一句,因为这里使

用的是GETUTCDATE(),即以UTC 时间(通用协调时间或格林尼治标准时间)表示的系统当前日期。所以在本

地数据库中的相应的[LastEditDate],[CreationDate]字段中的数据都比我机器上的时间早个小时(因为我的

机器时间设置在“东八区”) 。这里可修改为GETDATE()即可。

好了,聊到这里,今天的内容就差不多了,相应大家对“只同步新更改和增量更改”这种同步方式所生成的

代码清楚了一些。下面再简要说明一下SnapShot(快照方式)方式的生成文件(SyncSnapData.sync)。

相比较“只同步新更改和增量更改”方式,快照方式的结构与其大同小异。区别主要体现在了服务器端的

SyncAdapter类上。大家可以看一下源码中的dnt_topicsSyncAdapter类的InitializeCommands方法即可,

因为快照方式不用创建[LastEditDate],[CreationDate] 等用于比较差异的字段。所以在查询条件上(where)

要精简了不少(没有了关于[LastEditDate] , [CreationDate]等字段的比较和更新操作)。另外就是其只有

SelectIncrementalInsertsCommand命令对象而没有其余的几个对象(SelectConflictDeletedRowsCommand,

SelectIncrementalUpdatesCommand等,因为整表同步时用不上了)。

好了,今天的内部代码很多,但对照ado.net同步框架图,相应大家心里已经有数了。其余在MSF设计向

导所生成的代码中,还包括一类文件,即相应表的数据集(dataset)文件。这类文件中包括了对客户端数据

进行操作(CRUD)的一些通用方法(本地Adapter提供),以及序列化,数据集的Clone,相应表的实体类

对象(TypedTableBase类型),本地事务绑定等,并最终以TableAdapterManager类的方式进行相关实

例封装和绑定。相关内容可以参数DEMO中的如下即可:

SqlCeDB\BiDirectSynceDataSet.Designer.cs文件

SqlCeDB\LocalDataSet_Topic.Designer.cs文件

今天的内容就先到这里了,有兴趣的朋友可以在回复中进行讨论。

原文链接:http://www.cnblogs.com/daizhj/archive/2008/11/17/1335185.html

作者: daizhj, 代震军

Tags: 微软同步框架,ado.net,sqlce

网址: http://daizhj.cnblogs.com/

DEMO下载,请点击这里:)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: