【问题标题】:Comparing two datasets比较两个数据集
【发布时间】:2011-07-30 04:37:56
【问题描述】:

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

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

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

ds1.Merge(ds2);

changesDataSet = myData.GetChanges(DataRowState.Modified);

RowState 未被更改。我知道它正在修改数据,因为我故意在 MySQL 上的测试数据库上进行了更改,并在我调用合并后看到了更改。

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

【问题讨论】:

    标签: .net merge dataset compare


    【解决方案1】:

    我最初建议使用 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) 更粗、更乱;仍在使用 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()。

    【讨论】:

    • 是的,我用 true 试过了,但还是不行。我会再试一次。
    • @Terry 你是对的,ds2 中的行状态需要已经标记才能工作。我用两种可能的算法修改了这个答案,并把它变成了一个社区维基。希望其他一些读者可以改进其中一个以满足您的需求。
    猜你喜欢
    • 2015-07-10
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多