为什么我必须复制我的代码来处理两个同步的 MSSQL 数据库

Why do I have to duplicate my code to handle two synced MSSQL databases

我正在编写一个应用程序,具有 SQL 服务器连接。这种连接不是很稳定,所以我决定使用 Microsoft Sync Framework,它非常好。 我的问题是,当我在本地和服务器数据库之间切换时,我必须使用两倍的数据集和表适配器,而且我必须更改所有 winform 数据源(例如:组合框)。

我想实现的是在两个数据库之间轻松切换。 我有一个完整的工作代码,但我认为它可以更好。

初始化代码:

int timeout = 5;
public Form1()
{
    Program.ChangeConnectionString("TESTDBConnectionString", "Data Source=ip\engine;Initial Catalog=TESTDB;Persist Security Info=True;User ID=usr;Password=psw; Connect Timeout = " + timeout);
    Program.ChangeConnectionString("localConnectionString", "Data Source = (LocalDB)\MSSQLLocalDB; AttachDbFilename = \local.mdf; Integrated Security = True; Connect Timeout = " + timeout);
    InitializeComponent();
}

更新(和连接检查)代码:

private void UpdateDB()
{
    CheckServer();
    this.tbl_SyncTestTableAdapter1.Fill(this.localDataSet1.tbl_SyncTest);
    if (Program.IsOnline)
    {
        this.tbl_SyncTestTableAdapter.Fill(this.tESTDBDataSet.tbl_SyncTest);
        tblSyncTestBindingSource.DataSource = tESTDBDataSet.tbl_SyncTest;
        tblSyncTestBindingSource1.DataSource = tESTDBDataSet.tbl_SyncTest;
        tblSyncTestBindingSource2.DataSource = tESTDBDataSet.tbl_SyncTest;
        tblSyncTestBindingSource4.DataSource = tESTDBDataSet.tbl_SyncTest;
        dataGridView2.Visible = true;
        Sync();
    }
    else
    {
        tblSyncTestBindingSource.DataSource = localDataSet1.tbl_SyncTest;
        tblSyncTestBindingSource1.DataSource = localDataSet1.tbl_SyncTest;
        tblSyncTestBindingSource2.DataSource = localDataSet1.tbl_SyncTest;
        tblSyncTestBindingSource4.DataSource = localDataSet1.tbl_SyncTest;
        dataGridView2.Visible = false;
        label8.Text = "OFFLINE";
    }
}

示例数据库操作:

private void button3_Click(object sender, EventArgs e)
{
    string[] val = new string[] { comboBox2.Text, textBox5.Text, textBox4.Text };
    int ival = (int)comboBox2.SelectedValue;
    CheckServer();
    if (Program.IsOnline) tbl_SyncTestTableAdapter.Update(val[0], val[1], val[2], ival);
    else tbl_SyncTestTableAdapter1.Update(val[0], val[1], val[2], ival);
    UpdateDB();
}

如果您需要更多代码,请告诉我,但我认为其他代码无关紧要。

编辑,同步代码:

private void Sync()
{
    label8.Text = "SYNCING...";
    new Task(() =>
    {
        ProvisionServer();
        ProvisionLocal();
        SqlConnection serverConn = new SqlConnection(Properties.Settings.Default["TESTDBConnectionString"].ToString());
        SqlConnection localConn = new SqlConnection(Properties.Settings.Default["localConnectionString"].ToString());
        SyncOrchestrator syncOrchestrator = new SyncOrchestrator();
        syncOrchestrator.LocalProvider = new SqlSyncProvider("TestScope", localConn);
        syncOrchestrator.RemoteProvider = new SqlSyncProvider("TestScope", serverConn);
        syncOrchestrator.Direction = SyncDirectionOrder.DownloadAndUpload;
        SyncOperationStatistics syncStats = syncOrchestrator.Synchronize();
        Console.WriteLine("Start Time: " + syncStats.SyncStartTime);
        Console.WriteLine("Total Changes Uploaded: " + syncStats.UploadChangesTotal);
        Console.WriteLine("Total Changes Downloaded: " + syncStats.DownloadChangesTotal);
        Console.WriteLine("Complete Time: " + syncStats.SyncEndTime);
        Console.WriteLine(String.Empty);
        this.BeginInvoke((Action)(() =>
        {
            label8.Text = "SYNCED";
            this.tbl_SyncTestTableAdapter.Fill(this.tESTDBDataSet.tbl_SyncTest);
            this.tbl_SyncTestTableAdapter1.Fill(this.localDataSet1.tbl_SyncTest);
        }));
    }).Start();
}

存在 DataAdapter 模式,因此您可以 Adapt 针对不同的场景,而不必 implement/duplicate 在整个应用程序中使用相同的逻辑。在您的情况下,您只对选择正确的适配器实现感兴趣。

如果这是您唯一的表单,您可以引入一个 属性 来获取适当的 DataAdapter 并在整个过程中使用它。

// Adapter will give you an interface
// to either your local store
// or your online store
private IDataAdapter Adapter 
{
   get 
   {
       IDataAdapter _adapter = null;
       CheckServer();
       if (Program.IsOnline) 
       {
            _adapter = new SqlDataAdapter(selectcommand, onlineconnection);
       }
       else
       {
            _adapter = new  SqlCeDataAdapter(selectCommand, offlineConnection);
       }
       return _adapter
   }   
} 

您的其他方法只能处理一个数据集:

private void UpdateDB()
{
    this.Adapter.Fill(this.localDataSet1);
    // you don't need to change any bindings ...
}

以及您的数据库操作:

private void button3_Click(object sender, EventArgs e)
{
    string[] val = new string[] { comboBox2.Text, textBox5.Text, textBox4.Text };
    // if the Adapter has changed here
    // the dataset might hold different states
    // so it might hold on Update where an Insert is needed
    // in that case use some logic to Fill a new Dataset and merge that
    // with the current one
    this.Adapter.Update(this.localDataSet1); // the values from the dataset will be stored.
}

但是既然你已经公开了你的同步代码,你为什么不直接总是连接到你的本地数据库,然后让同步框架处理updates/inserts 在本地和中央数据库中都需要。将在线和离线场景的逻辑带到您选择 DataAdapter 的地方首先违背了同步框架的目的。