在Schema更改后,DB不会重新初始化为本地订户

时间:2009-07-08 13:07:32

标签: c# sql-server winforms replication

首先,我将概述我的问题,以防有人有替代修复。

问题:

我有一个使用 MergeReplication 的winform应用。除非我需要对5 Tables 上的主键进行更改,否则此功能非常有效。我从文章中删除了它们,然后进行了更改。然后我将它们重新添加到文章并将 Publication 设置为 Reintilialize All

不幸的是,这不起作用。 当我去运行订阅计划时,它告诉我订阅 InValid

编辑1

我在这里有更正/补充。我在复制监视器中遇到的实际错误是这样的 - >

Error messages:
The schema script 'tblCaseNotes_4.sch' could not be propagated to the subscriber. (Source: MSSQL_REPL, Error number: MSSQL_REPL-2147201001)
Get help: http://help/MSSQL_REPL-2147201001
Could not drop object 'dbo.tblCaseNotes' because it is referenced by a FOREIGN KEY constraint. (Source: MSSQLServer, Error number: 3726)
Get help: http://help/3726

这似乎很重要,因为这意味着我的MergeRepl同步过程正在尝试重新初始化,但由于以下问题而无法进行。

我能够在我的机器上修复它的方法是使用 MSSSMS 来删除数据库,然后运行我的程序,创建一个数据库并同步它。遗憾的是,由于远程连接关闭的安全原因,我没有MSSSMS访问所有远程用户SQL Express安装。

我的想法:

创建一个运行.sql脚本的小程序,以删除本地计算机上的数据库。阿拉; DROP DATABASE MyDB这只是测试阶段,因此不需要保存数据。

不幸的是,我不知道如何让程序这样做。

守则:

这是我的程序加载时运行的代码。它负责创建本地数据库和订阅(如果它们尚未存在)。然后检查它们是否需要同步并在需要时启动Pull Sync。我包含它是因为我的解决方案可能是对此代码的更改。

我将此代码称为 - >

MergeRepl matrixMergeRepl = new MergeRepl(SystemInformation.ComputerName + "\\SQLEXPRESS","WWCSTAGE","MATRIX","MATRIX","MATRIX");
matrixMergeRepl.RunDataSync();

MergeRepl位于 - >

之下
public class MergeRepl
{
    // Declare nessesary variables
    private string subscriberName;
    private string publisherName;
    private string publicationName;
    private string subscriptionDbName;
    private string publicationDbName;
    private MergePullSubscription mergeSubscription;
    private MergePublication mergePublication;
    private ServerConnection subscriberConn;
    private ServerConnection publisherConn;
    private Server theLocalSQLServer;
    private ReplicationDatabase localRepDB;

    public MergeRepl(string subscriber, string publisher, string publication, string subscriptionDB, string publicationDB)
    {
        subscriberName = subscriber;
        publisherName = publisher;
        publicationName = publication;
        subscriptionDbName = subscriptionDB;
        publicationDbName = publicationDB;

        //Create connections to the Publisher and Subscriber.
        subscriberConn = new ServerConnection(subscriberName);
        publisherConn = new ServerConnection(publisherName);


        // Define the pull mergeSubscription
        mergeSubscription = new MergePullSubscription
                                {
                                    ConnectionContext = subscriberConn,
                                    DatabaseName = subscriptionDbName,
                                    PublisherName = publisherName,
                                    PublicationDBName = publicationDbName,
                                    PublicationName = publicationName
                                };

        // Ensure that the publication exists and that it supports pull subscriptions.
        mergePublication = new MergePublication
                               {
                                   Name = publicationName,
                                   DatabaseName = publicationDbName,
                                   ConnectionContext = publisherConn
                               };

        // Create the local SQL Server instance
        theLocalSQLServer = new Server(subscriberConn);
        // Create a Replication DB Object to initiate Replication settings on local DB
        localRepDB = new ReplicationDatabase(subscriptionDbName, subscriberConn);

        // Check that the database exists locally
        CreateDatabase(subscriptionDbName);
    }

    /// <exception cref="ApplicationException">There is insufficient metadata to synchronize the subscription.Recreate the subscription with the agent job or supply the required agent properties at run time.</exception>
    public void RunDataSync()
    {
        // Keep program from appearing 'Not Responding'
        ///// Application.DoEvents();

        // Does the needed Databases exist on local SQLExpress Install
        /////CreateDatabase("ContactDB");

        try
        {
            //  Connect to the Subscriber
            subscriberConn.Connect();

            // if the Subscription exists, then start the sync
             if (mergeSubscription.LoadProperties())
             {
                 // Check that we have enough metadata to start the agent
                 if (mergeSubscription.PublisherSecurity != null || mergeSubscription.DistributorSecurity != null)
                 {
                     //  Synchronously start the merge Agent for the mergeSubscription
                     //  lblStatus.Text = "Data Sync Started - Please Be Patient!";
                     mergeSubscription.SynchronizationAgent.Synchronize();
                 }
                 else
                 {
                     throw new ApplicationException("There is insufficient metadata to synchronize the subscription." +
                         "Recreate the subscription with the agent job or supply the required agent properties at run time.");
                 }
             }
             else
             {
                 // do something here if the pull mergeSubscription does not exist
                 // throw new ApplicationException(String.Format("A mergeSubscription to '{0}' does not exist on {1}", publicationName, subscriberName));
                 CreateMergeSubscription();
             }
        }
        catch (Exception ex)
        {
            // Implement appropriaate error handling here
            throw new ApplicationException("The subscription could not be synchronized.  Verify that the subscription has been defined correctly.", ex);
            //CreateMergeSubscription();
        }
        finally
        {
            subscriberConn.Disconnect();
        }
    }

    /// <exception cref="ApplicationException"><c>ApplicationException</c>.</exception>
    public void CreateMergeSubscription()
    {
        // Keep program from appearing 'Not Responding'
        // Application.DoEvents();

        try
        {

            if (mergePublication.LoadProperties())
            {
                if ((mergePublication.Attributes & PublicationAttributes.AllowPull) == 0)
                {
                    mergePublication.Attributes |= PublicationAttributes.AllowPull;
                }

                // Make sure that the agent job for the mergeSubscription is created.
                mergeSubscription.CreateSyncAgentByDefault = true;

                // Create the pull mergeSubscription at the Subscriber.
                mergeSubscription.Create();

                Boolean registered = false;

                // Verify that the mergeSubscription is not already registered.
                foreach (MergeSubscription existing in mergePublication.EnumSubscriptions())
                {
                    if (existing.SubscriberName == subscriberName
                        && existing.SubscriptionDBName == subscriptionDbName
                        && existing.SubscriptionType == SubscriptionOption.Pull)
                    {
                        registered = true;
                    }
                }
                if (!registered)
                {
                    // Register the local mergeSubscription with the Publisher.
                    mergePublication.MakePullSubscriptionWellKnown(
                        subscriberName, subscriptionDbName,
                        SubscriptionSyncType.Automatic,
                        MergeSubscriberType.Local, 0);
                }
            }
            else
            {
                // Do something here if the publication does not exist.
                throw new ApplicationException(String.Format(
                    "The publication '{0}' does not exist on {1}.",
                    publicationName, publisherName));
            }
        }
        catch (Exception ex)
        {
            // Implement the appropriate error handling here.
            throw new ApplicationException(String.Format("The subscription to {0} could not be created.", publicationName), ex);

        }
        finally
        {
            publisherConn.Disconnect();
        }
    }

    /// <summary>
    /// This will make sure the needed DataBase exists locally before allowing any interaction with it.
    /// </summary>
    /// <param name="whichDataBase">The name of the DataBase to check for.</param>
    /// <returns>True if the specified DataBase exists, False if it doesn't.</returns>
     public void CreateDatabase(string whichDataBase)
    {
        Database db = LocalDBConn(whichDataBase, theLocalSQLServer, localRepDB);

        if (!theLocalSQLServer.Databases.Contains(whichDataBase))
        {
            //Application.DoEvents();
            // Create the database on the instance of SQL Server.
            db = new Database(theLocalSQLServer, whichDataBase);
            db.Create();

        }

        localRepDB.Load();
        localRepDB.EnabledMergePublishing = false;
        localRepDB.CommitPropertyChanges();

        if (!mergeSubscription.LoadProperties())
        {
            CreateMergeSubscription();
        }

    }

    private Database LocalDBConn(string databaseName, Server server, ReplicationDatabase replicationDatabase)
    {
        return server.Databases[replicationDatabase.Name];
    }

    /// <summary>
    /// Checks for the existence of the Publication.  If there is one it verifies Allow Pull is set
    /// </summary>
    /// <returns>True if Publication is present. False if not.</returns>
    public bool CheckForPublication()
    {
        // If LoadProperties() returns TRUE then the Publication exists and is reachable
        if (mergePublication.LoadProperties())
            return true;

        if ((mergePublication.Attributes & PublicationAttributes.AllowPull) == 0)
        {
            mergePublication.Attributes |= PublicationAttributes.AllowPull;
        }

        return false;
    } // end CheckForPublication()

    /// <summary>
    /// Checks for the existence of a Subscription.
    /// </summary>
    /// <returns>True if a Subscription is present.  False if not</returns>
    public bool CheckForSubscription()
    {
        // Check for the existence of the Subscription
        return mergeSubscription.IsExistingObject;
    } // end CheckForSubscription()
}

Guerdon(奖励):

这对我来说非常重要,所以即使我是一个火红的白痴,并且有一个超级简单的解决方案,我将为正确答案添加赏金。

编辑2

我创建了这个以尝试首先删除订阅....但它仍然在DROP DB部分上出错,说它正在使用...

    class Program
{
    static void Main(string[] args)
    {
        DropSubscription();
        DropDB();
    }

    private static void DropSubscription()
    {
        ServerConnection subscriberConn = new ServerConnection(".\\SQLEXPRESS");
        MergePullSubscription mergePullSubscription = new MergePullSubscription("MATRIX","WWCSTAGE","MATRIX","MATRIX",subscriberConn);

        mergePullSubscription.Remove();
    }

    private static void DropDB()
    {
        SqlCommand cmd;
        string sql;

        string dbName = "MATRIX";

        SqlConnection sqlConnection = new SqlConnection("Server=.\\SQLEXPRESS;Initial Catalog="+ dbName + ";Integrated Security=True;User Instance=False");
        sqlConnection.Open();
        sql = "DROP DATABASE " + dbName;
        cmd = new SqlCommand(sql,sqlConnection);
        cmd.ExecuteNonQuery();
        sqlConnection.Close();
    }
}

2 个答案:

答案 0 :(得分:4)

如果我已正确理解您的“原始”问题,那么您需要先创建新的发布快照,然后才能重新初始化。这样,您所做的任何结构更改都将应用于订阅者。

有关详细信息,请参阅Adding Articles to and Dropping Articles from Existing Publications,并按照合并复制的具体步骤进行操作。

答案 1 :(得分:4)

如果您正处于测试阶段(我当然不建议在生产系统上进行重大的架构更改),那么只需将订阅和数据库放在订阅者计算机上并重新开始。如果你可以通过SSMS连接到它们那么你可以从那里做到;或者如果你有物理访问权限,你可以使用SQLCMD。

我有使用SMO删除订阅和数据库的代码,但必须在订阅者上运行。如果您认为它会有所帮助,请告诉我,我会发布它。

编辑添加:好的,代码如下。我现在没有时间清理它,所以它是原始的。 RaiseSyncManagerStatus是一种将状态显示回UI的方法,因为这些方法是异步调用的。希望这会有所帮助 - 带上guerdon。 : - )

    public void DropSubscription()
    {
        try
        {
            RaiseSyncManagerStatus(string.Format("Dropping subscription '{0}'.", _publicationName));
            Server srv = new Server(_subscriberName);
            MergePullSubscription sub = GetSubscription(srv.ConnectionContext);
            // Remove if it exists
            // Cannot remove from publisher because sysadmin or dbo roles are required
            if (sub.LoadProperties() == true)
            {
                sub.Remove();
                RaiseSyncManagerStatus("Subscription dropped.");

                RaiseSyncManagerStatus("Removing subscription registration from the publisher.");
                Server srvPub = new Server(_publisherName);
                MergePublication pub = GetPublication(srvPub.ConnectionContext);
                // Remove the subscription registration
                pub.RemovePullSubscription(srv.Name, _subscriberDbName);
            }
            else
            {
                RaiseSyncManagerStatus("Failed to drop subscription; LoadProperties failed.");
            }
        }
        catch (Exception ex)
        {
            RaiseSyncManagerStatus(ex);
            throw;
        }
    }


    public void DropSubscriberDb()
    {
        try
        {
            RaiseSyncManagerStatus(string.Format("Dropping subscriber database '{0}'.", _subscriberDbName));

            if (SubscriptionValid())
            {
                throw new Exception("Subscription exists; cannot drop local database.");
            }

            Server srv = new Server(_subscriberName);
            Database db = srv.Databases[_subscriberDbName];

            if (db == null)
            {
                RaiseSyncManagerStatus("Subscriber database not found.");
            }
            else
            {
                RaiseSyncManagerStatus(string.Format("Subscriber database state: '{0}'.", db.State));
                srv.KillDatabase(_subscriberDbName);
                RaiseSyncManagerStatus("Subscriber database dropped.");
            }
        }
        catch (Exception ex)
        {
            RaiseSyncManagerStatus(ex);
            throw;
        }
    }