以编程方式创建和执行合并复制

时间:2009-06-02 20:26:09

标签: c# .net winforms refactoring replication

让我先说明我现在意识到我是多么愚蠢。我已经开发了1年(到今天),这是我写的第一件事。我现在已经回到它,我不能做它的正面或反面。它曾经在一个非常简单的应用程序上工作,但那是在不久之前。

具体来说,LocalDBConn使用out会遇到问题,但就我而言,我记不清为什么。

指导,指针,重构,打击头部都是欢迎和赞赏!

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

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

    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, out theLocalSQLServer, out localRepDB, out db);


        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 void LocalDBConn(string databaseName, out Server server, out ReplicationDatabase replicationDatabase, out Database db)
    {
        db = server.Databases[replicationDatabase.Name];
    }

    /// <summary>
    /// Checks for the existince of the Publication.  If there is one it verify's 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()
}

编辑1

Opps,我忘记了具体的错误。在serverreplicationDatabase我收到“Out参数可能在访问”

之前未初始化
        private void LocalDBConn(string databaseName, out Server server, out ReplicationDatabase replicationDatabase, out Database db)
    {
        db = server.Databases[replicationDatabase.Name];
    }

3 个答案:

答案 0 :(得分:2)

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

此方法不会构建,因为在方法返回之前未初始化out parameters。 out参数允许调用者将未实例化的对象传递给方法,然后该方法必须在返回之前通过所有路径初始化(不包括方法抛出异常)。基本上,out参数是方法声明“我将在返回之前实例化此对象”的语句。在LocalDBConn中,你没有这样做。

在C#3.0语言规范中,详见5.1.6。

答案 1 :(得分:2)

看起来你可以安全地删除了。

我不确定如何编译,除非它可能是VS2003并且编译器没有检查这种类型的错误。

从MSDN:虽然作为out参数传递的变量在传递之前不必初始化,但是在方法返回之前需要调用方法来赋值。

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

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

然后将CreateDatabase中的代码更新为:

Database db;
LocalDBConn(whichDataBase, theLocalSQLServer, localRepDB, out db);

Database db = LocalDBConn(whichDataBase, theLocalSQLServer, localRepDB);

答案 2 :(得分:1)

所有编译器都告诉您,Server和ReplicationDatabase是输出参数,但在从LocalDBConn方法返回之前,您没有为它们分配任何内容。

当使用out参数时,你应该对它们执行空检查,以确保它们已经在方法之外初始化,如果没有初始化它们。