1

好的,所以我需要获取两个数据行的键值配对差异。简而言之,我正在发送一封电子邮件,让用户知道他们对其个人资料进行了特定更改。我已经知道行是不同的,因为我正在使用SequenceEqual来确定。

目前我已经编写并调试了以下代码:

if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
    .Where((o, i) =>
    {
        if (o == null && updatedRow[i] == null) { return false; }
        else if (o == null && updatedRow[i] != null) { return true; }
        else if (o.Equals(updatedRow[i])) { return false; }
        return true;
    })
    .Select((o, i) =>
    {
        return new AppServices.NotificationData
        {
            Key = updatedRow.Table.Columns[i].ColumnName,
            Value = Convert.ToString(updatedRow[i])
        };
    }).ToList();

但是这段代码有两个问题:

  1. 这对我来说似乎效率很低,因为它会遍历 中的每个值,ItemArray然后在值不同时构建一个键值对
  2. 它实际上不起作用,因为i发送到的Select不正确(例如,如果第二列更改,1则发送到的索引Select实际上是0. 老实说,这是有道理的,但我不确定如何得到我想要的想在这里。

约束:我想在这里使用 LINQ。

注意:我只比较两行(即它不会通过行列表)。

对于我在这里尝试做的事情,合适的 LINQ 语句是什么?

更新:真的感觉我只需要使用:

currentRow.ItemArray.Intersect(updatedRow.ItemArray)

但问题是我不知道那是什么字段,所以我无法构建键值对。换句话说,我只取回差异,但我不知道索引是什么,所以我无法根据这些值获取列名。

4

3 回答 3

3

老实说,使用for循环不会失去太多代码清晰度。

public IEnumerable<AppServices.NotificationData> GetUpdates(DataRow currentRow, DataRow updatedRow)
{
    if (currentRow.ItemArray.SequenceEqual(updatedRow)) yield break;

    var length = currentRow.ItemArray.Length;
    for(var i = 0; i < length; i++)
    {
        var currentCol = currentRow[i];
        var updatedCol = updatedRow[i];

        if (currentCol == null && updatedCol == null) continue;
        else if (currentCol == null && updatedCol != null) continue;
        else if (currentCol.Equals(updatedCol)) continue;

        yield return new AppServices.NotificationData
                     {
                        Key = updatedRow.Table.Columns[i].ColumnName,
                        Value = Convert.ToString(updatedCol)
                     };
    }
}
于 2013-09-09T13:48:36.013 回答
1
var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
        || (r.Row != null && updatedRow[r.Index] != null
        && !r.Row.Equals(updatedRow[r.Index])))
    .Select(r => new
    {
        Key = updatedRow.Table.Columns[r.Index].ColumnName,
        Value = Convert.ToString(updatedRow[r.Index])
    }).ToList();
于 2013-09-09T13:39:38.933 回答
1

一般来说,我认为在 LINQ 中使用数组索引值是一种“代码气味”,这是一个很好的例子,说明了原因:Where 子句在生成新的值序列时破坏了 Select 子句正在处理的错觉和以前一样的收藏。

现在可以快速解决这个问题(尽管我认为这还不是正确的解决方案),基本上是交换您的 Where 和 Select 子句:

if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
    .Select((o, i) =>
    {
        if (o == null && updatedRow[i] == null || o.Equals(updatedRow[i])) { return null; }
        else return new AppServices.NotificationData
        {
            Key = updatedRow.Table.Columns[i].ColumnName,
            Value = Convert.ToString(updatedRow[i])
        };
    }).Where(o => o != null).ToList();
于 2013-09-09T13:40:50.950 回答