2

这个问题已经在Stack Overflow上被问过好几次了,但在将其标记为重复之前,请先看看我的问题。

我正在尝试比较两个数据库表的更改值。
基本上,我试图通过比较来记录更新的数据。

这些是我需要比较更改的数据库表:

我的数据表

在表 2、3Id和 4 中得到了更新的值。我需要获取这些值并将它们存储在第三个数据库表中。如果我为此获得一些通用类会好得多。

另外,如果有人添加更多内容并告诉我如何比较相同类型的 2 个列表的更改并仅返回具有更改值的该类型列表?

在这里,我要求更多,但如果有人可以帮助我。

4

1 回答 1

-1

比较器

.net BCL 包含可用于声明满足您需求的自定义比较的抽象:

class RowDataComparer : IEqualityComparer<DataRow>
{
    public bool Equals(DataRow x, DataRow y)
    {
        // add check for nulls, different ItemArray length, whatever
        var xv = x.ItemArray;
        var yv = y.ItemArray;

        for (int i = 0; i < xv.Length; i++)
            if(xv[i] == null && yv[i] == null)
               continue; 
            else if (xv[i]==null || !xv[i].Equals(yv[i]))
                return false;
        return true;
    }

    public int GetHashCode(DataRow obj) 
        => obj[0]?.GetHashCode() ?? 0;
}

在这个比较器中你需要知道的一些有趣的事情:

1)GetHashCode实现是愚蠢的而且相当无用,但它有效;)。阅读此线程以了解如何正确实现它。阅读此线程以了解它的使用位置以及在您的情况下实施它是否如此重要。

2) 我确实检查了 的值null,因为我讨厌NullReferenceExceptions。但是,这里可能不是这种情况,因为 null 值DataRow被替换为DBNull.Value

3)我不使用运算符==来比较对象。它可能适用于实现的引用类型Equals/GetHashCode,否则它将比较引用。装箱的值总是有不同的引用,所以如果你有例如整数列,==将不起作用。试试这个来感受不同:Console.WriteLine((object)42 == (object)42)Console.WriteLine(((object)42).Equals((object)42))

差异

假设架构是相同的,键是整数,您不关心额外/缺失的行,您可以使用如下所示的内容:

class RowsComparer
{
    Dictionary<int, DataRow> _leftRows;
    Dictionary<int, DataRow> _rightRows;
    HashSet<int> _commonKeys;

    private static Dictionary<int, DataRow>  toRows(DataTable table)
        => table.Rows.OfType<DataRow>().ToDictionary(r => (int)r.ItemArray[0]);

    public RowsComparer(DataTable left, DataTable right)
    {
        _leftRows = toRows(left);
        _rightRows = toRows(right);

        _commonKeys = new HashSet<int>(_leftRows.Keys.Intersect(_rightRows.Keys));
    }

    public IEnumerable<DataRow> Diffs()
        => _commonKeys.Select(k => _rightRows[k]).Except(_leftRows.Values, new RowDataComparer());

    public IEnumerable<DataRow> Extra()
        => _leftRows.Where(kv => !_commonKeys.Contains(kv.Key)).Select(kv => kv.Value);

    public IEnumerable<DataRow> Missing()
        => _rightRows.Where(kv => !_commonKeys.Contains(kv.Key)).Select(kv => kv.Value);
}
于 2019-10-05T02:16:42.500 回答