我在DataSet中有一个带有列C1(PK),C2和C3(唯一值)的DataTable dt1,删除了一些行后,我将进行AcceptChanges。我有另一个DataTable dt2,其结构与dtA相同。我想删除dtA中存在于dtB中的行,比较C3(唯一值)并执行AcceptChanges。
我可以达到非常接近,但不是我想做的事情除了以下情况(从here学到的):
var a = dt1.AsEnumerable().Select(r => r.Field<Guid>("C3"));
var b = dt2.AsEnumerable().Select(r => r.Field<Guid>("C3"));
var c = a.Except(b);
这种方法的问题是,我只得到属于C3列的值列表。我可以像here所示做更多的事情,但是我将再次拥有一个新的DataTable,我仍然不会更改现有的dt1表。
我想到的第二种方法是做类似下面的事情:
foreach (DataRow r1 in ds1.Tables[0].Rows)
{
foreach(DataRow r2 in dt2.Rows)
{
if (r1.Field<Guid>("Guid1") == r2.Field<Guid>("Guid2"))
{
r1.Delete();
}
}
}
这里一旦删除了行,我就会收到一条错误消息“此行已从表中删除且没有任何数据。”我在这里缺少什么?
我也有一种感觉,可能有更好的方法这样做,只是不知道大声笑。
答案 0 :(得分:5)
我收到一条错误消息“此行已从表中删除并且确实已删除 没有任何数据'我在这里缺少什么?
你有两个循环 - 外部和内部。你有两个问题。第一个是找到匹配时删除行。在内循环的下一次迭代中,您试图获取已删除行的值,这将抛出异常。但是即使你在删除行后会破坏内部循环,你也会遇到另一个问题 - 修改你要枚举的行。因此,您的代码应如下所示:
foreach (DataRow r1 in dt1.Rows.Cast<DataRow>().ToArray()) // save rows to array
{
foreach (DataRow r2 in dt2.Rows)
{
if (r1.Field<Guid>("C3") == r2.Field<Guid>("C3"))
{
r1.Delete();
break; // break inner loop
}
}
}
但是我会使用LINQ方法 - 通过连接id字段上的行来获取要删除的行,然后从表中删除它们:
var rowsToDelete = from r1 in dt1.AsEnumerable()
join r2 in dt2.AsEnumerable()
on r1.Field<Guid>("C3") equals r2.Field<Guid>("C3")
select r1;
foreach(DataRow row in rowsToDelete.ToArray())
row.Delete(); // marks row as deleted;
注意:在现有DataRow上使用Delete
方法后,其RowState将变为已删除。行仍然是已删除,直到您调用AcceptChanges
,从表中删除行。