繁体   English   中英

C# - 两个数据表比较。 获取更新、删除和创建的行(新)

[英]C# - Two DataTable comparison. Get Rows which are Updated, Deleted and Created(New)

我有 2 个数据表:第一个数据表是今天创建的,第二个数据表是昨天创建的。 每个 DataTable 包含超过 100K 行和 30 列。 我有一个独特的专栏 - “Master_ID”

我想比较和减去(今天的DataTable - 昨天的DataTable)并得到更新,删除和新建的行。 我想进行完整的逐行比较。

输出 -> 字典 <string, List DataRow >

  1. Dictionary <"New Data Rows", List DataRow >
  2. Dictionary <"Updated Data Rows", List DataRow >
  3. Dictionary <"Deleted Data Rows", List DataRow >

我正在寻找一种省时的方法,可能使用 LINQ。

这段代码可能会对您有所帮助。 它获取新DataTable中的每一行并在旧DataTable中查找它(以获取创建和更新的行),然后获取旧表中未在新表中找到的所有行(以获取已删除的行)。 如果您的表包含超过 100K 行,它将工作得非常慢,因此您最好将它放在一个单独的线程中。

如果它们的Master_ID列相同,我的代码会将两个不同的行视为一个更新的行。

DataTable oldTable, newTable; // Put there your tables
Dictionary<int, DataRow> deletedRows, newRows = new Dictionary<int, DataRow>(); // Here will be the result (key — row's Master_ID, value — the row)
var updatedRows = new Dictionary<int, Tuple<DataRow, DataRow>>(); // Here will be the result (key — row's Master_ID, value — tuple (first item — old row version, second item — new row version))

var commonIds = new List<int>();

foreach (var row in newTable.Rows) {
  var id = row["Master_ID"];

  if (oldTable.Contains(id)) {
    commonIds.Add((int)id);

    var rowInOldTable = oldTable.Rows.Find(id);

    foreach (var column in oldTable.Columns) {
      if (row[column] != rowInOldTable[column]) {
        updatedRows.Add((int)id, Tuple.Create<DataRow, DataRow>(rowInOldTable, row));
        break;
      }
    }
  } else {
    newRows.Add((int)id, row);
  }
}

deletedRows = (from row in oldTable.Rows
               where !commonIds.Contains((int)row["Master_ID"]))
              .ToDictionary<DataRow, int>(row => (int)row["Master_ID"]);

可能最有效的方法之一是使用类似字典的集合来查明行标识符是否是新的,我会使用ILookup<TKey, TValue>

public static Dictionary<string, List<DataRow>?> GetChanges(DataTable dtNew, DataTable dtOld, string masterKeyName, StringComparer masterKeyComparer = null)
{
    IEqualityComparer<string> comparer = masterKeyComparer ?? StringComparer.Ordinal;
    ILookup<string, DataRow> newKeyLookup = dtNew.AsEnumerable().ToLookup(r => r.Field<string>(masterKeyName), comparer!)!;
    ILookup<string, DataRow> oldKeyLookup = dtOld.AsEnumerable().ToLookup(r => r.Field<string>(masterKeyName), comparer!)!;
    List<DataRow> updatedRows = new();
    List<DataRow> newRows = new();
    List<DataRow> deletedRows = new();

     foreach (var x in newKeyLookup)
     {
        List<DataRow> existingRows = oldKeyLookup[x.Key].ToList();
        if (existingRows.Any())
        {
            // potential update, check if there are changes:
            var allChangedRows = x.Where(r => !existingRows.Contains(r, DataRowComparer.Default));
            updatedRows.AddRange(allChangedRows);
        }
        if (!existingRows.Any())
        {
            newRows.AddRange(x);
        }
    }

    foreach (var x in oldKeyLookup)
    {
        if (!newKeyLookup[x.Key].Any())
        {
            deletedRows.AddRange(x);
        }
    }

    return new Dictionary<string, List<DataRow>?>
    {
        {"New Data Rows", newRows},
        {"Updated Data Rows", updatedRows},
        {"Deleted  Data Rows", deletedRows},
    };
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM