我有一个具有MyDataTable _dt
作为成员的父WinForm。 MyDataTable类型是在Visual Studio 2005中的“类型化数据集”设计器工具中创建的(MyDataTable继承自DataTable)_dt
通过ADO.NET从db填充。根据表单中用户交互的变化,我从表中删除了一行,如下所示:
_dt.FindBySomeKey(_someKey).Delete();
稍后,_dt
按值传递给对话框表单。从那里,我需要扫描所有行来构建一个字符串:
foreach (myDataTableRow row in _dt)
{
sbFilter.Append("'" + row.info + "',");
}
问题是在删除后执行此操作时,会抛出以下异常:
DeletedRowInaccessibleException: Deleted row information cannot be accessed through the row.
我目前正在使用的工作(感觉就像是黑客攻击)如下:
foreach (myDataTableRow row in _dt)
{
if (row.RowState != DataRowState.Deleted &&
row.RowState != DataRowState.Detached)
{
sbFilter.Append("'" + row.info + "',");
}
}
我的问题:这是正确的方法吗?为什么foreach循环访问已通过Delete()
方法标记的行?
答案 0 :(得分:14)
Delete
method标记要删除的行;在您致电AcceptChanges
之前,该行实际上并未删除。
而是拨打_dt.Rows.Remove(_dt.FindBySomeKey(_someKey))
,这也会接受更改
信不信由你,Rows.Remove
will completely remove the row, whereas row.Delete()
won't。 击>
请注意,如果您致电Rows.Remove
,该行将永久消失,并且不会被DataAdapter从数据库中删除。
在C#3中,您可以使用以下扩展方法替换if
语句:
///<summary>Gets the rows in a typed DataTable that have not been deleted.</summary>
public static EnumerableRowCollection<TRow> CurrentRows<TRow>(this TypedTableBase<TRow> table) where TRow : DataRow {
return table.Where(r => r.RowState != DataRowState.Deleted);
}
foreach (myDataTableRow row in _dt.CurrentRows())
{
...
这是一个C#2版本:
static class Utils {
public static IEnumerable<TRow> CurrentRows(IEnumerable<TRow> table) where TRow : DataRow {
foreach(TRow row in table) {
if (row.RowState != DataRowState.Deleted)
yield return row;
}
}
}
foreach (myDataTableRow row in Utils.CurrentRows(_dt))
{
您还可以将此函数放入类型表的分部类中:
partial class MyTable {
public IEnumerable<MyRow> CurrentRows() { return Utils.CurrentRows(this); }
}
答案 1 :(得分:3)
您在迭代中跳过行的操作是正确的,当我遍历可能被修改的DataTable时,我会定期检查RowState。
在某些情况下,我认为您希望行被标记为已删除之前的原始行值。检索特定数据行值时有一个辅助索引选项。
string st = dr["columnname", DataRowVersion.Original].ToString(); // c#
dim st As String = dr("columnname", DataRowVersion.Original).ToString() ' vb.net
我过去曾多次坚持这一次。
就GetChanges(RowState)方法而言,不要忘记检查null返回,如果没有该RowState的行,则返回的DataTable为null(我认为它应该返回一个表零行)
答案 2 :(得分:2)
你必须检查:
_dt.DefaultView.RowStateFilter
我认为默认设置不会显示已删除的行,也许您会在某处更改它。
您始终可以创建一个额外的RowView并控制其过滤器并在View上循环。
答案 3 :(得分:1)
使用GetChanges():
foreach (myDataTableRow row in _dt.GetChanges(DataRowState.Added))
{
sbFilter.Append("'" + row.info + "',");
}
如果您想要全部添加和修改,请在添加和修改时使用按位OR:
foreach (myDataTableRow row in
_dt.GetChanges(DataRowState.Added | DataRowState.Modified))
{
sbFilter.Append("'" + row.info + "',");
}
答案 4 :(得分:0)
我不确定这一点,但我认为如果在删除一行或多行后调用_dt.AcceptChanges()
,则在遍历数据表的Rows集合时,您将不会“看到”已删除的行。