2011-04-05 229 views
0

我有一個需要從Oracle數據導入到MySQL。我需要使用Oracle的數據更新MySQL數據。我有代碼設置從兩個資源獲取數據,但我有問題找出更新信息的最佳方法。比較兩個數據集

我已經試過DataSet.Merge,但實際上並不正確檢舉該RowState的。我曾希望使用:

ds1 = GetMySQLData(); 
ds2 = GetOracleData(); 

ds1.Merge(ds2); 

changesDataSet = myData.GetChanges(DataRowState.Modified); 

RowState未被更改。我知道它正在修改數據,因爲我故意在MySQL的測試數據庫上改變了一些內容,並在我調用合併之後看到了更改。

是否存在已知的方式(算法),我可以用它來測試對彼此的數據集,插入,更新,刪除記錄?

回答

0

我最初提出呼籲與preserveChanges = true的合併()過載,但如果DS2已經排指示其與DS1的不同規定,只適用。正如你在你的問題中所說的,那就是你需要完成的。那麼,算法?這裏有兩個:乾淨,簡單,明顯的方式;並改編爲sort-merge join。周圍有檢查DS2的每一行沒辦法,但第二算法試圖減少預期的數據將被下令DS1搜索量。

1)簡單,乾淨,明顯的;使用DataRowCollection.Find(pk)和object []。SequenceEqual()。每個表中都需要一個主鍵,但不需要排序數據,主鍵的類型也不重要。

for (int i = 0; i < ds2.Tables.Count; i++) 
{ 
    foreach (DataRow dr in ds2.Tables[i].Rows) 
    { 
     DataRow drOrig = ds1.Tables[i].Rows.Find(dr[0]); 
     if (drOrig != null) 
     { 
      if (!drOrig.ItemArray.SequenceEqual(dr.ItemArray)) 
      { 
       dr.SetModified(); 
      } 
     } 
     else 
     { 
      dr.SetAdded(); 
     } 
    } 
} 

ds1.Merge(ds2); 

2)粗砂,混亂;仍然使用object []。SequenceEqual()。數據必須是有序的,儘管'pk'/行標識符不必是唯一的。但是,它的類型必須爲每個單獨的表格所知,並且如果類型不同,則不能簡單地遍歷表格。

// Assuming first column of each table is int, primary key; and that all data are ordered by pk. 
for (int i = 0; i < ds2.Tables.Count; i++) 
{ 
    int indexDs1 = 0 
    int indexDs2 = 0; 
    DataRow nextDs1Row = ds1.Tables[i].Rows[indexDs1]; 
    DataRow nextDs2Row = ds2.Tables[i].Rows[indexDs2]; 
    int nextDs1Pk = (int)nextDs1Row[0]; 
    int nextDs2Pk = (int)nextDs2Row[0]; 
    while ((indexDs1 < ds1.Tables[i].Rows.Count) && (indexDs2 < ds2.Tables[i].Rows.Count)) 
    { 
     if (nextDs1Pk == nextDs2Pk) 
     { 
      // Set row state to modified if any differences exist. 
      if (!nextDs1Row.ItemArray.SequenceEqual(nextDs2Row.ItemArray)) 
      { 
       nextDs2Row.SetModified(); 
      } 
      // Advance both iterators by one row. 
      indexDs1++; 
      if (indexDs1 < ds1.Tables[i].Rows.Count) 
      { 
       nextDs1Row = ds1.Tables[i].Rows[indexDs1]; 
       nextDs1Pk = (int)nextDs1Row[0]; 
      } 
      indexDs2++; 
      if (indexDs2 < ds2.Tables[i].Rows.Count) 
      { 
       nextDs2Row = ds2.Tables[i].Rows[indexDs2]; 
       nextDs2Pk = (int)nextDs2Row[0]; 
      } 
     } 
     else if (nextDs1Pk < nextDs2Pk) 
     { 
      // Advance through ds1, doing nothing, until the next pk of ds2 is reached. 
      do 
      { 
       indexDs1++; 
       if (indexDs1 < ds1.Tables[i].Rows.Count) 
       { 
        nextDs1Row = ds1.Tables[i].Rows[indexDs1]; 
        nextDs1Pk = (int)nextDs1Row[0]; 
       } 
       else 
       { 
        break; 
       } 
      } while (nextDs1Pk < nextDs2Pk); 
     } 
     else //nextDs1Pk > nextDs2Pk 
     { 
      // Advance through ds2, setting row state to added, until the next pk of ds1 is reached. 
      do 
      { 
       nextDs2Row.SetAdded(); 
       indexDs2++; 
       if (indexDs2 < ds2.Tables[i].Rows.Count) 
       { 
        nextDs2Row = ds2.Tables[i].Rows[indexDs2]; 
        nextDs2Pk = (int)nextDs2Row[0]; 
       } 
       else 
       { 
        break; 
       } 
      } while (nextDs1Pk > nextDs2Pk); 
     } 
    } 
} 

如果你的機器多任務好,你並不需要強制執行的設定各表的外鍵約束,我會設置每個表的行分析作爲一個單獨的任務,開始他們都在並行,然後在任務完成時將表格逐一合併。如果這足以使算法1符合您的要求,我會以簡單的名義與它一起使用。它使用find()和SequenceEqual()方法可能是高度優化和算法2並沒有在我的測試更快的執行。如果兩者都不夠快,並且您對數據有所瞭解,則可以改進SequenceEqual()。

+0

是我真正嘗試過了,仍然沒有工作。我會再試一次。 – VoltaicShock 2011-04-05 18:00:45

+0

@Terry你說的沒錯,在DS2的行狀態將需要已經被標記爲工作。我用兩種可能的算法修改了這個答案,並將其作爲一個社區維基。希望其他一些讀者可以改進其中一個足以滿足您的需求。 – Kimberly 2011-04-06 04:41:45