我有两个XML数据集,ds1和ds2。我使用.ReadXML(name,XmlReadMode.ReadSchema)读取这些数据集。我试图通过使用如下所示的合并数据集来获得具有两者之间差异的DiffGram。

DataSet ds3 = new DataSet();
ds3.Merge(ds1);
ds3.AcceptChanges();
ds3.Merge(ds2);

DataSet ds4 = ds3.GetChanges();

ds4.WriteXml("ds4.xml", XmlWriteMode.DiffGram);


ds1和ds2每个都包含多个元素。我通过复制ds1文件并修改其中一条记录来创建ds2。

但是,当我在执行后查看ds4.xml时,它显示了ds1中的所有记录集和ds2中的所有记录(因此它显示了重复的条目),并且ds2更新被列为... diffgr:hasChanges = “插入”>。看来这只是插入,而不是更新现有记录。

如何使ds4仅显示在ds2中所做的更改?

最佳答案

这种插入与更新的行为通常是由于缺少定义的主键而发生的。您在桌子上设置了主键吗?这就是合并过程中列匹配的方式。 Per MSDN(重点是我的):


  将新的源数据集合并到
  目标,任何带有
  DataRowState的值保持不变,
  修改或删除与
  具有相同主键的目标行
  价值观。源行带有
  已添加的DataRowState值是
  与新的目标行匹配
  与新的主键值相同
  源行。


因此,应为每个DataTable设置PrimaryKey property。几年前,我在MSDN DataTable.Merge页面上写了一个详细的示例。您可以在此处查看该内容:Merge using Primary Keys for Expected Results

此方法的简要示例:

DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("Customer", typeof(string));
dt1.PrimaryKey = new[] { dt1.Columns["ID"] };
dt1.Rows.Add(new object[] { 1, "Ahmad" });

DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(int));
dt2.Columns.Add("Customer", typeof(string));
dt2.PrimaryKey = new[] { dt2.Columns["ID"] };
dt2.Rows.Add(new object[] { 1, "Mageed" });

// try without primary keys and it'll add a new record
dt1.Merge(dt2);


编辑:关于您的评论,您可以拒绝表中的以下代码来对合并行中的更改进行更改,这些更改实际上并没有真正改变。接受DataTable的方法会更整洁。在调用DataTable.AcceptChanges() method之前使用此代码很重要,否则行状态将被丢弃。

使用LINQ:

foreach (DataRow row in dt1.Rows)
{
    if (row.RowState == DataRowState.Modified)
    {
        var original = dt1.Columns.Cast<DataColumn>()
                          .Select(c => row[c, DataRowVersion.Original]);

        bool isUnchanged = row.ItemArray.SequenceEqual(original);
        if (isUnchanged)
        {
            row.RejectChanges();
        }
    }
}


如果不选择LINQ:

foreach (DataRow row in dt1.Rows)
{
    if (row.RowState == DataRowState.Modified)
    {
        bool isUnchanged = true;
        foreach (DataColumn col in dt1.Columns)
        {
            if (!row[col.ColumnName].Equals(row[col.ColumnName, DataRowVersion.Original]))
            {
                isUnchanged = false;
                break;
            }
        }

        if (isUnchanged)
        {
            row.RejectChanges();
        }
    }
}


完成后,您可以呼叫dt1.AcceptChanges()

10-08 13:15