我有两个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中所做的更改?
答案 0 :(得分:3)
这种插入与更新的行为通常是由于缺少定义的主键而发生的。你有没有在桌子上设置主键?这就是合并期间列匹配的方式。 Per MSDN(强调我的):
将新的源DataSet合并到 目标,任何带有的源行 DataRowState值为Unchanged, 已修改或已删除匹配 目标行具有相同的主键 值即可。源行与 添加的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()
。