2011-04-05 163 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