今天是个好日子,
我知道,我所说的版本现在已经过时了,但这是我在工作场所坚持使用的工具。这是我在 StackOverflow 上的第一个问题,我希望我能得到正确的格式,呵呵 ;-) 请原谅我的长文,我习惯于提供很多细节,从某种意义上说,我觉得我的细节越多提供更准确的答案可能是;-)
在 IT 领域工作近 10 年以来,我总是能够通过谷歌搜索精心挑选的关键字和表达式来找到我的问题的答案(即我的问题的解决方案)。好吧,看起来前面提到的 Sync Framework 要么对 Internet 社区不太熟悉,要么对于大多数凡人来说,尝试理解其最简单的概念真的很痛苦。经过广泛的研究,我必须找到一个使用 Sync Framework 1.0 和 C# 语言同步 SQL Express 的单个简单示例,甚至在 MSDN 上都没有!我对 ASP.NET / C# 相当陌生,但我了解这些概念,并且我有一个可以正常工作的 Web 应用程序,可以成功地从 SQL Server 2008 数据库存储和检索数据。客户已经使用了两年了。我们现在要求客户端能够使他们的数据脱机并能够脱机更新,然后与服务器同步。UPDATE、INSERT 和 DELETE 将在两端发生。
我试图找到的非常简单(或者我认为):使用 SQL Server 更改跟踪信息(不是自定义更改跟踪)来同步服务器(SQL Server 2008)和客户端计算机(SQL Server 2008 Express,不是精简版)。最简单的情况是包含几列的单个表。我对理解 SQL Server 部分相当有信心,并且我已经准备好数据库的两端以接收来自客户端 Web 应用程序的同步请求(启用更改跟踪,PrimaryKeyID 具有数据类型 GUID,服务器上的应用程序用户帐户具有 VIEW_CHANGE_TRACKING 权限等)
我知道 Web 应用程序充当两者之间的接口并管理同步会话(在 C# 中)。我很天真地认为唯一剩下要做的就是提供两个连接字符串,告诉要同步哪些表并指定双向同步。显然,这比那个更复杂嘿嘿。在一次绝望的尝试中,我尝试将我的代码基于 Microsoft 的以下代码并将其调整为 SQL Express(该示例适用于 Compact)。我差点认输,可耻地低下头:-(
http://msdn.microsoft.com/en-us/library/bb726015%28v=sql.100%29.aspx
基于上述(第二部分“使用 SQL Server 更改跟踪的完整示例”),我删除了我不需要的所有内容:与密码、统计信息和对数据应用更改的代码相关的内容。为了清楚起见,我还删除了 MS 的众多评论行。我已经在 SSMS 中执行脚本的两端手动应用了 SQL Server 本身的更改(因此必须生成更改跟踪信息,并且在 Web 应用程序请求同步时可用)。问题1:我这样说有错吗?最后,我更改了一些东西以尝试使用与 SQL Express 相关的对象而不是 Compact。
问题 2:Microsoft 的代码显然能够判断它是该副本的初始(第一次)同步还是后续同步。我不知道它怎么可能!
最后,以最简单的形式留下的代码如下(带有问题 3、4、5 ;-),但显示了一些错误。我非常感谢您的帮助。欢迎任何意见和/或建议。我敢肯定,如果/当这个问题得到解决,它将使很多人受益。我将继续研究它(老板不会给我选择;-)我保证如果我成功同步,我会在这里发布解决方案!
谢谢,祝大家有美好的一天!
最亲切的问候,
关注
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
//using System.Data.SqlServerCe;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.Server;
//using Microsoft.Synchronization.Data.SqlServerCe;
namespace some_namespace
{
public class SyncProgram
{
public SyncProgram()
{
// empty constructor
}
public static bool MainSync() // Entry point, say, called by a Sync button on an ASPX page.
{
bool boolSyncRes = false; // tells whether sync was a success or not
// Initial sync: they create a new instance of the Orchestrator.
ZyxySyncOrchestrator zyxySyncOrchestrator = new ZyxySyncOrchestrator();
// Subsequent synchronization.
// They don't. there was only irrelevant stats stuff here.
boolSyncRes = true;
return boolSyncRes;
}
}
public class ZyxySyncOrchestrator : SyncOrchestrator
{
public ZyxySyncOrchestrator()
{
Utility util = new Utility();
this.LocalProvider = new ZyxyServerSyncProvider(); // QUESTION 3: ??? cannot implicitly convert type DbServerSyncProvider to Microsoft.Synchronization.SyncProvider
//Instantiate a server synchronization provider and specify it
//as the remote provider for this synchronization agent.
this.RemoteProvider = new ZyxyServerSyncProvider(); // cannot implicitly convert type DbServerSyncProvider to Microsoft.Synchronization.SyncProvider
// QUESTION 4: Is the following code actually creating the base (user) table ZyxySync
// (as opposed to its change tracking metadata table)??
// I wasn't sure whether this part of the code on Microsoft's webpage was part of
// populating the db with sample data and structure or if it's really meant to deal with
// the change tracking metadata.
SyncTable zyxySyncTable = new SyncTable("ZyxySync");
zyxySyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;
zyxySyncTable.SyncDirection = SyncDirection.DownloadOnly;
this.Configuration.SyncTables.Add(zyxySyncTable);
}
}
//Create a class that is derived from Microsoft.Synchronization.Server.DbServerSyncProvider.
public class ZyxyServerSyncProvider : DbServerSyncProvider
{
public ZyxyServerSyncProvider()
{
Utility util = new Utility();
SqlConnection serverConn = new SqlConnection(util.ServerConnString);
this.Connection = serverConn;
//Retrieve a new anchor value from the server. We use a timestamp value
//that is retrieved and stored in the client database.
//During each sync the new and last anchor values are used to determine the set of changes
SqlCommand selectNewAnchorCommand = new SqlCommand();
string newAnchorVariable = "@" + SyncSession.SyncNewReceivedAnchor;
selectNewAnchorCommand.CommandText =
"SELECT " + newAnchorVariable + " = change_tracking_current_version()";
selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.BigInt);
selectNewAnchorCommand.Parameters[newAnchorVariable].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Connection = serverConn;
this.SelectNewAnchorCommand = selectNewAnchorCommand;
//Create a SyncAdapter for the ZyxySync table by using
//the SqlSyncAdapterBuilder.
// Specify a name for the SyncAdapter that matches the
// the name specified for the corresponding SyncTable.
SqlSyncAdapterBuilder zyxyBuilder = new SqlSyncAdapterBuilder(serverConn);
zyxyBuilder.TableName = "dbo.ZyxySync";
zyxyBuilder.ChangeTrackingType = ChangeTrackingType.SqlServerChangeTracking;
SyncAdapter zyxySyncAdapter = zyxyBuilder.ToSyncAdapter();
zyxySyncAdapter.TableName = "ZyxySync";
this.SyncAdapters.Add(zyxySyncAdapter);
}
}
// Class derived from Microsoft.Synchronization.Data.Server.DbServerSyncProvider
// QUESTION 5: Or should have I used the two below? I believe they only apply to SQL Compact...
//Microsoft.Synchronization.Data.ClientSyncProvider
//Microsoft.Synchronization.Data.ServerSyncProvider
//http://msdn.microsoft.com/en-us/library/microsoft.synchronization.data.clientsyncprovider%28v=sql.100%29.aspx
//http://msdn.microsoft.com/en-us/library/microsoft.synchronization.data.server.dbserversyncprovider%28d=printer,v=sql.100%29.aspx
public class ZyxyClientSyncProvider : DbServerSyncProvider
{
public ZyxyClientSyncProvider()
{
Utility util = new Utility();
SqlConnection clientConn = new SqlConnection(util.ClientConnString);
this.Connection = clientConn;
}
}
public class Utility
{
public string ClientConnString
{
get { return @"Data Source=localhost\LocalExpressInstance;Initial Catalog=DatabaseName;User ID=UserName;Password=WontTellYou;"; }
}
public string ServerConnString
{
get { return @" Data Source=ServerName\ServerInstance;Initial Catalog=DatabaseName;User ID=UserName;Password=WontTellYou;"; }
}
}
}