首先,我将概述我的问题,以防有人有替代修复。
我有一个使用 MergeReplication 的winform应用。除非我需要对5 Tables 上的列和主键进行更改,否则此功能非常有效。我从文章中删除了它们,然后进行了更改。然后我将它们重新添加到文章并将 Publication 设置为 Reintilialize All 。
不幸的是,这不起作用。 当我去运行订阅计划时,它告诉我订阅是 InValid 。
我在这里有更正/补充。我在复制监视器中遇到的实际错误是这样的 - >
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()
}
这对我来说非常重要,所以即使我是一个火红的白痴,并且有一个超级简单的解决方案,我将为正确答案添加赏金。
我创建了这个以尝试首先删除订阅....但它仍然在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();
}
}
答案 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;
}
}