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

C# 以编程方式创建和执行合并复制,c#,.net,winforms,refactoring,replication,C#,.net,Winforms,Refactoring,Replication,让我先说一句,我现在意识到我是多么的愚蠢。我已经发展了一年(直到今天),这是我写的第一件事。我现在又回到这件事上来了,我不知道该怎么办。它曾经在一个非常简单的应用程序上工作过,但那是很久以前的事了 具体来说,我在使用out的LocalDBConn方面遇到了问题,但我一辈子都不记得为什么 指导,指针的,重构,拍打头部都是欢迎和赞赏的 public class MergeRepl { // Declare nessesary variables private str

让我先说一句,我现在意识到我是多么的愚蠢。我已经发展了一年(直到今天),这是我写的第一件事。我现在又回到这件事上来了,我不知道该怎么办。它曾经在一个非常简单的应用程序上工作过,但那是很久以前的事了

具体来说,我在使用
out
LocalDBConn
方面遇到了问题,但我一辈子都不记得为什么

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

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

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

当使用out参数时,应该对它们执行null检查,以确保它们已在方法外部初始化(如果未初始化)

private void LocalDBConn(string databaseName, out Server server, out ReplicationDatabase replicationDatabase, out Database db)
{
    db = server.Databases[replicationDatabase.Name];
}
此方法不会生成,因为在该方法返回之前未初始化。out参数允许调用方将未实例化的对象传递到方法中,然后该方法必须在返回之前通过所有路径初始化该对象(如果该方法引发异常则除外)。基本上,out参数是方法的一个语句,表示“我将在返回之前实例化这个对象”。在LocalDBConn中,您没有这样做


在C#3.0语言规范中,第5.1.6节对此进行了详细说明。

看起来您可以安全地删除out

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

From MSDN:虽然作为输出参数传递的变量在传递之前不必初始化,但在方法返回之前,被调用的方法必须赋值

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

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

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


对这没什么坏处。或者干脆放弃该方法,使用Database db=theLocalSQLServer.Databases[localRepDB.Name];实际上只是一种编码偏好。虽然我必须说,使用这种方法是很好的自我记录。
private Database LocalDBConn(string databaseName, Server server, 
     ReplicationDatabase replicationDatabase)
{
    return server.Databases[replicationDatabase.Name];
}
Database db;
LocalDBConn(whichDataBase, theLocalSQLServer, localRepDB, out db);
Database db = LocalDBConn(whichDataBase, theLocalSQLServer, localRepDB);