Microsoft Sync Framework:无法枚举 table 'Table Name' 的 RelationalSyncProvider 中的更改

Microsoft Sync Framework : Cannot enumerate changes at the RelationalSyncProvider for table 'Table Name'

看看下面的代码

这是我的 _cSynchronization Class,其中包含同步功能, 连接字符串中的 (500) 表示超时 = 500

public static class _cSynchronization
    {
        public static int transactionCount;
        public static uint BatchSize = 10000;
        public static uint MemorySize = 20000;

        public static List<string> _MGetAllTableList()
        {
            List<string> list = new List<string>();
            DataRowCollection _dr = _CObjectsofClasses._obj_CDatabase._MGetDataRows("Select TABLE_NAME From INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME <> N'AUTOBACKUPSET' AND TABLE_NAME <> N'BINDATA' AND TABLE_NAME <> N'_ATTENDANCESTATUS' AND TABLE_NAME NOT like '%_tracking%' AND TABLE_TYPE ='BASE TABLE' AND TABLE_NAME <> N'schema_info' AND TABLE_NAME <> N'scope_info' AND TABLE_NAME <> N'scope_config'  AND TABLE_NAME <> '_CLIENTNAME'  AND TABLE_NAME <> '_TABSETTING' AND TABLE_NAME <> '_EMPLOYEEPAYMENT1' AND TABLE_NAME <> '_LOCALCOMPANYINFO' ORDER BY TABLE_NAME");
            int a = 0;
            string x = "";
            if (_dr.Count > 0)
            {
                _CPubVar._value_I = 0;
                _CPubVar._MaxValue_I = _dr.Count + 2;
                _CPubVar._IsTableProcess_bool = true;
                foreach (DataRow _row in _dr)
                {
                    _CPubVar._value_I++;
                    _CPubVar._ProcessText_S = "Preparing Tables " + _CPubVar._value_I + " of " + _CPubVar._MaxValue_I;
                    x = _CObjectsofClasses._obj_CConvert._MConvertToString(_row[0]);
                    //  serverConn.Open();
                    list.Add(x);
                }
            }
            return list;
        }
        public static void SetUp(string _pTableName)
        {
            // Connection to  SQL Server database
            SqlConnection serverConn = new SqlConnection(_CObjectsofClasses._obj_CConnectionString._MGetServerConnectionString(500));
            // Connection to SQL client database
            SqlConnection clientConn = new SqlConnection(_CObjectsofClasses._obj_CConnectionString._MGetConnectionString(500));


            // Create a scope named "product" and add tables to it.
            DbSyncScopeDescription productScope = new DbSyncScopeDescription(_pTableName + "_SCOP");

            // Select the colums to be included in the Collection Object

            // Define the Products table.
            DbSyncTableDescription productDescription =
                                                    SqlSyncDescriptionBuilder.GetDescriptionForTable(_pTableName,serverConn);
            // Add the Table to the scope object.    
            productScope.Tables.Add(productDescription);

            // Create a provisioning object for "product" and apply it to the on-premise database if one does not exist.
            SqlSyncScopeProvisioning serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
            serverProvision.ObjectSchema = ".dbo";

            //
            serverProvision.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create);
            serverProvision.SetCreateTableDefault(DbSyncCreationOption.Skip);
            serverProvision.SetCreateProceduresDefault(DbSyncCreationOption.CreateOrUseExisting);
            serverProvision.SetCreateTrackingTableDefault(DbSyncCreationOption.CreateOrUseExisting);
            serverProvision.SetCreateTriggersDefault(DbSyncCreationOption.CreateOrUseExisting);

            if (!serverProvision.ScopeExists(_pTableName + "_SCOP"))
                serverProvision.Apply();

            // Provision the SQL client database from the on-premise SQL Server database if one does not exist.
            SqlSyncScopeProvisioning clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);


            if (!clientProvision.ScopeExists(_pTableName + "_SCOP"))
                clientProvision.Apply();

            // Shut down database connections.

            serverConn.Close();

            serverConn.Dispose();

            clientConn.Close();

            clientConn.Dispose();
        }
        public static List<_CSyncDetails> Synchronize(string _pScopeName, SyncDirectionOrder _pDirection)
        {
            // Connection to  SQL Server database
            SqlConnection serverConn = new SqlConnection(_CObjectsofClasses._obj_CConnectionString._MGetServerConnectionString(500));

            // Connection to SQL client database
            SqlConnection clientConn = new SqlConnection(_CObjectsofClasses._obj_CConnectionString._MGetConnectionString(500));

            List<_CSyncDetails> _Statics = new List<_CSyncDetails>();

            // Perform Synchronization between SQL Server and the SQL client.
            SyncOrchestrator syncOrchestrator = new SyncOrchestrator();

            // Create provider for SQL Server
            SqlSyncProvider serverProvider = new SqlSyncProvider(_pScopeName, serverConn);

            // Set the command timeout and maximum transaction size for the SQL Azure provider.
            SqlSyncProvider clientProvider = new SqlSyncProvider(_pScopeName, clientConn);


            clientProvider.CommandTimeout = serverProvider.CommandTimeout = 500;
            //Set memory allocation to the database providers
            clientProvider.MemoryDataCacheSize = serverProvider.MemoryDataCacheSize = MemorySize;


            //Set application transaction size on destination provider.
            serverProvider.ApplicationTransactionSize = BatchSize;


            //Count transactions
            serverProvider.ChangesApplied += new EventHandler<DbChangesAppliedEventArgs>(RemoteProvider_ChangesApplied);


            // Set Local provider of SyncOrchestrator to the server provider
            syncOrchestrator.LocalProvider = serverProvider;

            // Set Remote provider of SyncOrchestrator to the client provider
            syncOrchestrator.RemoteProvider = clientProvider;

            // Set the direction of SyncOrchestrator session to Upload and Download
            syncOrchestrator.Direction = _pDirection;

            // Create SyncOperations Statistics Object

            SyncOperationStatistics syncStats = syncOrchestrator.Synchronize();
            _Statics.Add(new _CSyncDetails { UploadChangesTotal = syncStats.UploadChangesTotal, SyncStartTime = syncStats.SyncStartTime, DownloadChangesTotal = syncStats.DownloadChangesTotal, SyncEndTime = syncStats.SyncEndTime });

            // Display the Statistics

            // Shut down database connections.

            serverConn.Close();

            serverConn.Dispose();

            clientConn.Close();

            clientConn.Dispose();
            return _Statics;

        }
  }

这里是我同步的函数

 private void _MSync()
        {

        _CPubVar._IsContinue = true;
        _CPubVar._PausebtnCondition = 0;
       // _cSynchronization._MClearSyncprovision();

        _CPubVar._Stop_bool = false;

        this.Text += " - Started at : " + DateTime.Now;
        string a = ""; 
        // Define the Products table.
        List<string> _Tablelist = new List<string>();
        Collection<string> _ColNames = new Collection<string>();
        _list1.Add(new _CSyncDetails { SyncStartTime = DateTime.Now });

        _Tablelist.AddRange(_cSynchronization._MGetAllTableList());

        SyncDirectionOrder _order = SyncDirectionOrder.Download;
        _CPubVar._MaxValue_I = (_Tablelist.Count * 2);
        _CPubVar._value_I = 0;
        foreach (string tbl in _Tablelist)
        {
            try
            {
                a = Regex.Replace(Environment.MachineName + Environment.UserName, @"[^0-9a-zA-Z]+", "").ToUpper() + "_" + tbl + "_SCOPE";
                _CPubVar._value_I++;
                _CPubVar._ProcessText_S = "Sync Tables " + _CPubVar._value_I + " of " + _CPubVar._MaxValue_I;   
                _cSynchronization.SetUp(tbl);

                if (_CPubVar._IsServerRunning_bool)
                {
                    _order = SyncDirectionOrder.DownloadAndUpload;
                }
                else
                {
                    if (tbl == "_BANK" || tbl == "_BANKACCOUNT" || tbl == "_CLIENTNAME" || tbl == "_PACKAGE" || tbl == "_PACKAGEDET" || tbl == "_PAYMENTEXPENCES" || tbl == "_PROJECT" || tbl == "_PROJECTDET" || tbl == "_REQUIREMENT" || tbl == "_REQUIREMENTDET" || tbl == "_SERVER" || tbl == "_UNIT" || tbl == "_ITEM" || tbl == "ManageUser" || tbl == "USERPERMISSION" || tbl == "USERROLE" || tbl == "USERROLEDET")
                    {
                        _order = SyncDirectionOrder.DownloadAndUpload;
                    }
                    else
                    {
                        _order = SyncDirectionOrder.Download;
                    }
                }
                _CPubVar._value_I++;
                _CPubVar._ProcessText_S = "Sync Tables " + _CPubVar._value_I + " of " + _CPubVar._MaxValue_I;


                if (tbl != "_COMPANYINFO")
                {
                    _list1.AddRange(_cSynchronization.Synchronize(tbl + "_SCOP", _order));
                }
                else
                {
                    if (_CPubVar._IsServerRunning_bool)
                    {
                        _list1.AddRange(_cSynchronization.Synchronize(tbl + "_SCOP", SyncDirectionOrder.DownloadAndUpload));
                    }
                }
            }
            catch (Exception exx)
            {
                _syncErr.Add(new _CSyncErrors { SyncErrorDateTime = DateTime.Now, SyncErrorMessage = exx.Message, SyncTableAlies = _CTableName._MgetTableAlies(tbl) });
                pictureBox1.Visible = label3.Visible = true;
                label3.Text = _syncErr.Count.ToString();
                Application.DoEvents();
                continue;
            }
        }
        thread.Abort(); 

    }

问题:

以上代码一次仅适用于一台 PC 同步(让 Take A)没有错误并完成。

一次一台 PC 同步(让 Take B)没有错误并完成。

但是当我尝试同时 运行 申请时(A 和 B 同时)然后对于一些 table 我得到

Cannot enumerate changes at the RelationalSyncProvider for table 'TableName'

运行状态

PC A      PC B      Result
YES        NO       No Error
NO         YES      No Error
YES        YES      Error

请注意,客户端我的数据库是 2008,服务器端我的数据库是 2012 我哪里错了

更新: 我在数据库中有 72 tables 并且下面的错误不是特定的 'TableName' 它可能是来自 72,

的任何 table

例如 Table1 给我错误,如果我重新 运行 应用程序完成同步后可能不会出现此错误。

Cannot enumerate changes at the RelationalSyncProvider for table 'TableName'

检查超时

八分钟可能不够。尝试将同步命令超时增加到一个荒谬的数字,看看是否是问题所在。

 clientProvider.CommandTimeout = 3000;
 serverProvider.CommandTimeout = 3000;

开启追踪

通过添加以下 system.diagnostics 段为您的应用程序编辑 app.config 文件。它将详细记录到 C:\MySyncTrace.txt.

<configuration>
  <system.diagnostics>
    <switches>
      <!--4-verbose.-->
      <add name="SyncTracer" value="4" />
    </switches>
    <trace autoflush="true">
      <listeners>
        <add name="TestListener"
             type="System.Diagnostics.TextWriterTraceListener"
             initializeData="c:\MySyncTrace.txt"/>
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

我的娱乐

我试图重现您遇到的错误。我创建了您要完成的任务的简化版本。它构建并成功同步了两个 SqlExpress 数据库。

不幸的是,我无法重现错误。这是我使用的设置和之后的测试用例。

模拟数据库创建脚本

USE Master;
GO

IF EXISTS (
        SELECT *
        FROM sys.databases
        WHERE NAME = 'SyncTestServer'
        )
    DROP DATABASE SyncTestServer
GO

CREATE DATABASE SyncTestServer;
GO

CREATE TABLE SyncTestServer.dbo.Table1 (Column1 VARCHAR(50) PRIMARY KEY)
CREATE TABLE SyncTestServer.dbo.Table2 (Column1 VARCHAR(50) PRIMARY KEY)

INSERT INTO SyncTestServer.dbo.Table1 (Column1)
VALUES ('Server Data in Table1')

INSERT INTO SyncTestServer.dbo.Table2 (Column1)
VALUES ('Server Data in Table2')

IF EXISTS (
        SELECT *
        FROM sys.databases
        WHERE NAME = 'SyncTestClient'
        )
    DROP DATABASE SyncTestClient
GO

CREATE DATABASE SyncTestClient;
GO

CREATE TABLE SyncTestClient.dbo.Table1 (Column1 VARCHAR(50) PRIMARY KEY)
CREATE TABLE SyncTestClient.dbo.Table2 (Column1 VARCHAR(50) PRIMARY KEY)

INSERT INTO SyncTestClient.dbo.Table1 (Column1)
VALUES ('Client Data in Table1')

INSERT INTO SyncTestClient.dbo.Table2 (Column1)
VALUES ('Client Data in Table2')

模拟控制台应用程序

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
using Microsoft.Synchronization;

namespace Whosebug_SyncFramework
{
    public class _CSyncDetails
    {
        public int UploadChangesTotal;
        public DateTime SyncStartTime;
        public int DownloadChangesTotal;
        public DateTime SyncEndTime;
    }

    public class Program
    {
        static void Main(string[] args)
        {
            _cSynchronization sync = new _cSynchronization();
            sync._MSync();

            Console.ReadLine();
        }
    }

    public class _cSynchronization
    {
        public static int transactionCount;
        public static uint BatchSize = 10000;
        public static uint MemorySize = 20000;
        public const string ServerConnString = 
            @"Data Source=.\SQLExpress;initial catalog=SyncTestServer;integrated security=True;MultipleActiveResultSets=True;";
        public const string ClientConnString = 
            @"Data Source=.\SQLExpress;initial catalog=SyncTestClient;integrated security=True;MultipleActiveResultSets=True;";

        public static List<string> _MGetAllTableList()
        {
            // I just created two databases that each have the following table
            // Synchronization is working
            List<string> list = new List<string>()
            {
                "Table1",
                "Table2"
            };
            return list;
        }

        public static void SetUp(string _pTableName)
        {
            // Connection to  SQL Server database
            SqlConnection serverConn =
                new SqlConnection(ServerConnString);
            // Connection to SQL client database
            SqlConnection clientConn =
                new SqlConnection(ClientConnString);

            // Create a scope named "product" and add tables to it.
            Console.WriteLine(_pTableName);
            DbSyncScopeDescription productScope = new DbSyncScopeDescription(_pTableName + "_SCOP");

            // Define the Products table.
            DbSyncTableDescription productDescription =
                                                    SqlSyncDescriptionBuilder.GetDescriptionForTable(_pTableName, serverConn);
            // Add the Table to the scope object.    
            productScope.Tables.Add(productDescription);

            // Create a provisioning object for "product" and apply it to the on-premise database if one does not exist.
            SqlSyncScopeProvisioning serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
            serverProvision.ObjectSchema = ".dbo";

            serverProvision.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create);
            serverProvision.SetCreateTableDefault(DbSyncCreationOption.Skip);
            serverProvision.SetCreateProceduresDefault(DbSyncCreationOption.CreateOrUseExisting);
            serverProvision.SetCreateTrackingTableDefault(DbSyncCreationOption.CreateOrUseExisting);
            serverProvision.SetCreateTriggersDefault(DbSyncCreationOption.CreateOrUseExisting);

            if (!serverProvision.ScopeExists(_pTableName + "_SCOP"))
                serverProvision.Apply();

            // Provision the SQL client database from the on-premise SQL Server database if one does not exist.
            SqlSyncScopeProvisioning clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);

            if (!clientProvision.ScopeExists(_pTableName + "_SCOP"))
                clientProvision.Apply();

            // Shut down database connections.
            serverConn.Close();
            serverConn.Dispose();
            clientConn.Close();
            clientConn.Dispose();
        }

        public static List<_CSyncDetails> Synchronize(string _pScopeName, SyncDirectionOrder _pDirection)
        {
            // Connection to  SQL Server database
            SqlConnection serverConn =
                new SqlConnection(ServerConnString);

            // Connection to SQL client database
            SqlConnection clientConn =
                new SqlConnection(ClientConnString);

            List<_CSyncDetails> _Statics = new List<_CSyncDetails>();

            // Perform Synchronization between SQL Server and the SQL client.
            SyncOrchestrator syncOrchestrator = new SyncOrchestrator();

            // Create provider for SQL Server
            SqlSyncProvider serverProvider = new SqlSyncProvider(_pScopeName, serverConn);

            // Set the command timeout and maximum transaction size for the SQL Azure provider.
            SqlSyncProvider clientProvider = new SqlSyncProvider(_pScopeName, clientConn);

            clientProvider.CommandTimeout = serverProvider.CommandTimeout = 500;
            //Set memory allocation to the database providers
            clientProvider.MemoryDataCacheSize = serverProvider.MemoryDataCacheSize = MemorySize;

            //Set application transaction size on destination provider.
            serverProvider.ApplicationTransactionSize = BatchSize;

            //Count transactions
            serverProvider.ChangesApplied += 
                new EventHandler<DbChangesAppliedEventArgs>(RemoteProvider_ChangesApplied);

            // Set Local provider of SyncOrchestrator to the server provider
            syncOrchestrator.LocalProvider = serverProvider;

            // Set Remote provider of SyncOrchestrator to the client provider
            syncOrchestrator.RemoteProvider = clientProvider;

            // Set the direction of SyncOrchestrator session to Upload and Download
            syncOrchestrator.Direction = _pDirection;

            // Create SyncOperations Statistics Object

            SyncOperationStatistics syncStats = syncOrchestrator.Synchronize();
            _Statics.Add(new _CSyncDetails
            {
                UploadChangesTotal = syncStats.UploadChangesTotal,
                SyncStartTime = syncStats.SyncStartTime,
                DownloadChangesTotal = syncStats.DownloadChangesTotal,
                SyncEndTime = syncStats.SyncEndTime
            });

            // Shut down database connections.
            serverConn.Close();
            serverConn.Dispose();
            clientConn.Close();
            clientConn.Dispose();
            return _Statics;
        }

        private static void RemoteProvider_ChangesApplied(object sender, DbChangesAppliedEventArgs e)
        {
            Console.WriteLine("Changes Applied");
        }

        public void _MSync()
        {
            // Define the Products table.
            List<string> _Tablelist = new List<string>();
            _Tablelist.AddRange(_cSynchronization._MGetAllTableList());

            foreach (string tbl in _Tablelist)
            {
                SetUp(tbl);
                _cSynchronization.Synchronize(tbl + "_SCOP", SyncDirectionOrder.DownloadAndUpload);
            }
        }
    }
}

Select 测试前后的陈述

SELECT * 
FROM SyncTestServer.dbo.Table1

SELECT * 
FROM SyncTestServer.dbo.Table2

SELECT * 
FROM SyncTestClient.dbo.Table1

SELECT * 
FROM SyncTestClient.dbo.Table2

同步前

这是同步前的数据库状态。

同步后

这是后来的状态。因此,同步似乎有效。

重新尝试删除服务器和三个并发同步

这是远程数据库的连接字符串。

public const string ServerConnString =
    @"data source=x0x0x0x0x0x.database.windows.net,1433;initial catalog=SyncTestServer01;user id=xoxoxox@xoxoxox;password=xoxoxoxoxox;MultipleActiveResultSets=True;";

这是模拟三个并发同步的修改。

public class Program
{
    public static string[] ClientConnString = new string[] 
        {
            @"Data Source=.\SQLExpress;initial catalog=SyncTestClient01;integrated security=True;MultipleActiveResultSets=True;"
            ,@"Data Source=.\SQLExpress;initial catalog=SyncTestClient02;integrated security=True;MultipleActiveResultSets=True;"
            ,@"Data Source=.\SQLExpress;initial catalog=SyncTestClient03;integrated security=True;MultipleActiveResultSets=True;"
        };

    static void Main(string[] args)
    {
        foreach (var connString in ClientConnString)
        {
            Action action = () =>
            {
                _cSynchronization sync = new _cSynchronization();
                sync._MSync(connString);
            };
            Task.Factory.StartNew(action);
        }

        Console.ReadLine();
    }
}

恐怕我无法重现您遇到的错误。请打开跟踪,然后 post 跟踪结果到您的问题。这样我们就可以分析跟踪并查看问题所在。