比较两个数据集

时间:2011-04-05 17:46:34

标签: .net merge dataset compare

我需要将数据从Oracle导入MySQL。我需要使用Oracle的数据更新MySQL数据。我有代码设置来从两个资源获取数据,但我遇到了找出更新信息的最佳方法的问题。

我尝试过DataSet.Merge,但实际上并没有正确标记RowState。我希望使用:

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

ds1.Merge(ds2);

changesDataSet = myData.GetChanges(DataRowState.Modified);

RowState没有被改变。我知道它正在修改数据,因为我故意在MySQL上的测试数据库上改变了一些内容,并在调用合并后看到了更改。

是否有一种已知的(算法)方法可以用来相互测试数据集并插入,更新,删除记录?

1 个答案:

答案 0 :(得分:0)

我最初建议使用preserveChanges = true调用Merge()重载,但只有当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)Grittier,更加干净;仍然使用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()。