比较两个DataRows,不包括某些列

时间:2014-05-09 12:44:02

标签: c# .net linq ado.net

我有两个DataTable,例如OriginalEntity和Entity。 接口应用程序修改实体dataTable的行。在保存时我想检查已修改或与OrigianlEntity不同的DataRows。 但是,我还需要排除几个字段,修改日期和其他审计字段。 目前我循环遍历每一行数据表,如下所示:

List<string> auditFields = new List<string>(){"createdon","modifiedon"};
string IdentityKeyName = "id";
object ent,orgEnt; 
foreach(string columnName in columnList) // ColumnList is List of columns available in datatable
{
    foreach(DataRow dr in Entity.Rows)
    {
        ent = dr[columnName];
        orgEnt = OriginalEntity.Select(IdentityKeyName + " = " + dr[IdentityKeyName].ToString())[0][columnName];
        if(!ent.Equals(orgEnt) && !auditFields.Contains(columnName))
        {
            isModified = true;
            break;
        }
    }
}

我只想要一种有效的方法来实现上述目标。请建议。

感谢大家的建议,这是我的(因为我没有定义主键)

解决方案:

public bool isModified(DataTable dt1, DataTable dt2, string IdentityKeyName)
{
    bool isModified = false;
    List<string> auditFields = new List<string>() { "createdon", "modifiedon" };
    isModified = isModified || (dt1.Rows.Count != dt2.Rows.Count);
    if(!isModified)
    {
        //Approach takes 150 ms to compare two datatable of 10000 rows and 24 columns each
        DataTable copyOriginalEntity = dt1.Copy();
        DataTable copyEntity = dt2.Copy();

        //Exclude field you don't want in your comparison -- It was my main task
        foreach(string column in auditFields)
        {
            copyOriginalEntity.Columns.Remove(column);
            copyEntity.Columns.Remove(column);
        }
        for(int i=0;i<copyOriginalEntity.Rows.Count;i++)
        {
            var origItems = copyOriginalEntity.Rows[i].ItemArray;
            var entityItem = copyEntity.Select(IdentityKeyName + " = " + copyOriginalEntity.Rows[i][dentityKeyName].ToString())[0].ItemArray;
            if(string.Concat(origItems) != string.Concat(entityItem)){ isModified = true; break; }
        }
    }
    return isModified;
}

1 个答案:

答案 0 :(得分:1)

您将不得不循环通过列进行比较。比较代码中的 ent.Equals(orgEnt)是否比较对象引用是否相同。这似乎不是你想要的,你想比较值。

public bool IsChanged(DataTable original, DataTable source, string idKeyName, params string[] ignoreColumns)
{
    // make sure "key" column exist in both
    if (!original.Columns.Contains(idKeyName) || !source.Columns.Contains(idKeyName))
    {
        throw new MissingPrimaryKeyException("Primary key column not found.");
    }

    // if source rows are not the same as original then something was deleted or added
    if (source.Rows.Count != original.Rows.Count)
    {
        return false;
    }

    // Get a list of columns ignoring passed in and key (key will have to be equal to find)
    var originalColumns =
        original.Columns.Cast<DataColumn>()
                .Select(c => c.ColumnName)
                .Where(n => !ignoreColumns.Contains(n) && n != idKeyName)
                .ToArray();

    // check to make sure same column count otherwise just fail no need to check
    var sourceColumnsCount =
        source.Columns.Cast<DataColumn>()
              .Select(c => c.ColumnName).Count(originalColumns.Contains);
    if (originalColumns.Length != sourceColumnsCount)
    {
        return false;
    }

    //Switch to linq
    var sourceRows = source.AsEnumerable();
    return sourceRows.All(sourceRow =>
        {
            // use select since not real key
            var originalCheck = original.Select(idKeyName + " = " + sourceRow[idKeyName]);
            if (originalCheck.Length != 1)
            {
                // Couldn't find key or multiple matches
                return false;
            }

            var originalRow = originalCheck.First();
            //Since using same array we can use linq's SequenceEqual to compare for us
            return
                originalColumns.Select(oc => sourceRow[oc])
                               .SequenceEqual(originalColumns.Select(oc => originalRow[oc]));
        });
}

可能会有一些微观优化,但我认为无论你需要检查每一列。