2016-08-04 203 views
1

我目前在使用MonoDevelop的Ubuntu上使用Mono,使用與數據庫中的表匹配的DataTable運行,並且應該嘗試更新它。正在更新MySQL返回受影響的行,但實際上並未更新數據庫

以下代碼使用從XML文件加載的數據集,該文件是從另一臺機器上的Dataset.WriteXML創建的。

try 
{ 
    if(ds.Tables.Contains(s)) 
    {       
     ds.Tables[s].AcceptChanges(); 
     foreach(DataRow dr in ds.Tables[s].Rows) 
      dr.SetModified(); // Setting to modified so that it updates, rather than inserts, into the database 
     hc.Data.Database.Update(hc.Data.DataDictionary.GetTableInfo(s), ds.Tables[s]); 
    } 
      } 
      catch (Exception ex) 
      { 
       Log.WriteError(ex); 
      } 

這是插入/更新到數據庫中的代碼。

public override int SQLUpdate(DataTable dt, string tableName) 
    { 
     MySqlDataAdapter da = new MySqlDataAdapter(); 
     try 
     { 
      int rowsChanged = 0; 
      int tStart = Environment.TickCount; 

      da.SelectCommand = new MySqlCommand("SELECT * FROM " + tableName); 
      da.SelectCommand.Connection = connection; 

      MySqlCommandBuilder cb = new MySqlCommandBuilder(da); 
      da.UpdateCommand = cb.GetUpdateCommand(); 
      da.DeleteCommand = cb.GetDeleteCommand(); 
      da.InsertCommand = cb.GetInsertCommand(); 
      da.ContinueUpdateOnError = true; 
      da.AcceptChangesDuringUpdate = true; 

      rowsChanged = da.Update(dt); 

      Log.WriteVerbose("Tbl={0},Rows={1},tics={2},", dt.TableName, rowsChanged, Misc.Elapsed(tStart)); 
      return rowsChanged; 
      catch (Exception ex) 
      { 
       Log.WriteError("{0}", ex.Message); 
       return -1 
      } 

我正在嘗試上面的代碼,而rowsChanged變爲4183,我正在編輯的行數。但是,當我使用HeidiSQL來檢查數據庫本身時,它根本不會改變任何內容。

有沒有我失蹤的一步?

編輯:或者,能夠覆蓋數據庫中的所有行也可以。這是使用USB記憶棒更新遠程計算機的設置,強制它匹配源數據表。

編輯2:添加更多代碼示例以顯示DT的來源。 DataTable在調用函數中預先填充,並且所有行都有DataRow.SetModified();應用。

編輯3:其他信息。該表正在填充來自XML文件的數據。在評論中建議嘗試修復。

編輯4:添加調用代碼,以防萬一。

謝謝你的幫助。

+0

MySQL服務器/連接通常會設置是否返回受影響的行或匹配的行;這可能是這兩種環境的有效設置不同。 – Uueerdo

+1

DT是什麼?它在別處填滿了嗎?它只是在代碼中出現。 – Plutonix

+0

添加了所需的信息。 – user3169698

回答

1

您可能想要查看的最簡單方法可能是對目標表進行截斷,然後簡單地將XML導入保存到它(關閉AI,以便在必要時使用導入的ID)。唯一的問題可能是有權這樣做。否則......

什麼你正在嘗試做的CAN 幾乎使用Merge方法來處理。但是,它不能/不會知道關於刪除的行。由於該方法在DataTables上執行,因此如果在master數據庫中刪除了一行,它將不會存在於XML抽取中(而RowState的是Deleted)。這些可以循環清除。

同樣,對於一個AI int,任何新行都可能獲得不同的PK。爲了防止這種情況,只需在目標數據庫中使用一個簡單的非AI PK,以便它可以接受任何數字。

的XML負載:

private DataTable LoadXMLToDT(string filename) 
{ 
    DataTable dt = new DataTable(); 
    dt.ReadXml(filename); 
    return dt; 
} 

合併代碼:

DataTable dtMaster = LoadXMLToDT(@"C:\Temp\dtsample.xml"); 
// just a debug monitor 
var changes = dtMaster.GetChanges(); 

string SQL = "SELECT * FROM Destination"; 
using (MySqlConnection dbCon = new MySqlConnection(MySQLOtherDB)) 
{ 
    dtSample = new DataTable(); 
    daSample = new MySqlDataAdapter(SQL, dbCon); 

    MySqlCommandBuilder cb = new MySqlCommandBuilder(daSample); 
    daSample.UpdateCommand = cb.GetUpdateCommand(); 
    daSample.DeleteCommand = cb.GetDeleteCommand(); 
    daSample.InsertCommand = cb.GetInsertCommand(); 
    daSample.FillSchema(dtSample, SchemaType.Source); 
    dbCon.Open(); 

    // the destination table 
    daSample.Fill(dtSample); 

    // handle deleted rows 
    var drExisting = dtMaster.AsEnumerable() 
       .Select(x => x.Field<int>("Id")); 
    var drMasterDeleted = dtSample.AsEnumerable() 
       .Where(q => !drExisting.Contains(q.Field<int>("Id"))); 

    // delete based on missing ID 
    foreach (DataRow dr in drMasterDeleted) 
     dr.Delete(); 

    // merge the XML into the tbl read 
    dtSample.Merge(dtMaster,false, MissingSchemaAction.Add); 

    int rowsChanged = daSample.Update(dtSample); 
} 

無論出於何種原因,rowsChanged因爲總共有行始終報告發生了許多變化。但是來自主/ XML數據表的更改會流向其他/目標表。

刪除代碼獲取現有ID的列表,然後通過新的XML表是否具有帶該ID的行來確定需要從目標DataTable中刪除哪些行。所有缺失的行都被刪除,然後合併表。

關鍵是dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);它合併dtMasterdtSample的數據。參數允許傳入的XML更改覆蓋另一個表中的值(並最終保存到數據庫)。


我不知道有些像非匹配AI的PK問題是一個大問題或沒有,但這似乎處理所有我能找到。實際上,你要做的是Database Synchronization。雖然有一張桌子,只有幾行,但上述內容應該可以工作。

+1

經過一些小小的編輯,Fill然後合併做了詭計!我也感謝你的刪除行的事情,儘管我們處理這個有點不同。在你來之前,這花了我8個小時的頭部劃傷! – user3169698

相關問題