4 Stimmen

DB wird nach Schema-Änderungen nicht auf lokale Abonnenten reinitialisiert

Zunächst werde ich mein Problem schildern, falls jemand eine alternative Lösung hat.

Das Problem:

Ich habe eine Winform-App, die Folgendes verwendet MergeReplication . Dies funktioniert hervorragend, außer dass ich Änderungen an der Spalten y Primärschlüssel am 5. Tische . Ich habe sie aus dem Artikel und habe dann meine Änderungen vorgenommen. Anschließend fügte ich sie erneut in die Artikel und setzen Sie die Veröffentlichung a Alle reintialisieren .

Leider funktioniert das nicht. Wenn ich die Abonnement-Programm Es sagt mir, dass die Abonnement es InValid .

EDIT 1

Ich habe hier eine Korrektur/Ergänzung. Die tatsächlichen Fehler, die ich im Replikationsmonitor erhalte, sind folgende -->

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

Dies scheint wichtig zu sein, denn es bedeutet, dass mein MergeRepl-Synchronisierungsprozess versucht, sich neu zu initialisieren, dies aber aufgrund des folgenden Problems nicht möglich ist.

Ich konnte das Problem auf meinem Rechner beheben, indem ich MSSSMS um die DB zu LÖSCHEN und dann mein Programm auszuführen, das eine DB erstellt und sie synchronisiert. Leider habe ich keinen MSSSMS-Zugang zu allen SQL-Express-Installationen von Remote-Benutzern, da Remote-Verbindungen aus Sicherheitsgründen deaktiviert sind.

Meine Idee:

Erstellen Sie ein kleines Programm, das ein .sql-Skript ausführt, um die DB auf dem lokalen Rechner zu LÖSCHEN. A la; DROP DATABASE MyDB Da es sich hierbei nur um die Testphase handelt, ist keine Datensicherung erforderlich.

Leider habe ich nicht die geringste Ahnung, wie man ein Programm dazu bringt, das zu tun.

Der Kodex:

Dies ist der Code, der beim Laden meines Programms ausgeführt wird. Er kümmert sich um die Erstellung der lokalen Datenbanken und des Abonnements, falls sie nicht bereits vorhanden sind. Er prüft dann, ob sie synchronisiert werden müssen, und löst bei Bedarf einen Pull-Sync aus. Ich füge es wegen der Möglichkeit ein, dass meine Lösung eine Änderung an diesem Code ist.

Ich rufe diesen Code folgendermaßen auf -->

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

MergeRepl ist unten -->

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()
}

Der Guerdon (Belohnung):

Das ist mir sehr wichtig, und selbst wenn ich ein Vollidiot bin und es eine supereinfache Lösung gibt, werde ich für die richtige Antwort ein Kopfgeld aussetzen.

EDIT 2

Ich habe dies erstellt, um zu versuchen und entfernen Sie die Abonnement erste....which es tut, aber immer noch Fehler aus auf den DROP DB-Teil sagen, es ist in Gebrauch ...

    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();
    }
}

4voto

John Sansom Punkte 40295

Wenn ich Ihr "ursprüngliches" Problem richtig verstanden habe, dann müssen Sie einen neuen Snapshot der Publikation erstellen, bevor diese neu initialisiert werden kann. Dadurch werden alle strukturellen Änderungen, die Sie vorgenommen haben, für die Abonnenten übernommen.

Ver Hinzufügen und Entfernen von Artikeln aus bestehenden Publikationen für weitere Informationen und befolgen Sie die spezifischen Schritte für die Merge-Replikation.

4voto

Jamie Ide Punkte 46985

Wenn Sie sich in der Testphase befinden (und ich empfehle sicherlich keine signifikanten Schemaänderungen auf einem Produktivsystem), dann löschen Sie einfach das Abonnement und die Datenbank auf den Abonnentenrechnern und beginnen Sie von vorne. Wenn Sie über SSMS eine Verbindung zu ihnen herstellen können, können Sie dies von dort aus tun; wenn Sie physischen Zugang zu ihnen haben, können Sie dies mit SQLCMD tun.

Ich habe einen Code zum Löschen von Abonnements und Datenbanken mit SMO, aber er muss auf dem Abonnenten ausgeführt werden. Lassen Sie mich wissen, wenn Sie denken, es wäre hilfreich, und ich werde es posten.

Bearbeitet um hinzuzufügen: OK, der Code steht unten. Ich habe im Moment keine Zeit, ihn zu bereinigen, also ist er unbearbeitet. RaiseSyncManagerStatus ist eine Methode zur Anzeige des Status auf der Benutzeroberfläche, da diese Methoden asynchron aufgerufen werden. Ich hoffe, das hilft - auf den Guerdon zu kommen :-)

    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;
        }
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X