我有两个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()
。