2010-04-26 20 views
7

Tengo una WinForm principal que tiene una MyDataTable _dt como miembro. El tipo MyDataTable se creó en la herramienta de diseño "conjunto de datos tipeados" en Visual Studio 2005 (MyDataTable hereda de DataTable) _dt se rellena desde un db a través de ADO.NET. Sobre la base de los cambios de la interacción del usuario en el formulario, elimino una fila de la tabla de esta manera:Acceso a las filas eliminadas de una DataTable

_dt.FindBySomeKey(_someKey).Delete();

Más tarde, _dt se pasa por valor a una forma de diálogo. A partir de ahí, tengo que buscar a través de todas las filas para construir una cadena:

  foreach (myDataTableRow row in _dt) 
      { 
       sbFilter.Append("'" + row.info + "',"); 
      } 

El problema es que al hacer esto después de un borrado, la excepción siguiente: DeletedRowInaccessibleException: Deleted row information cannot be accessed through the row.

El trabajo en torno a ese Actualmente estoy usando (que se siente como un truco) es la siguiente:

  foreach (myDataTableRow row in _dt) 
      { 
       if (row.RowState != DataRowState.Deleted && 
        row.RowState != DataRowState.Detached) 
       { 
        sbFilter.Append("'" + row.info + "',"); 
       } 
      } 

Mi pregunta: ¿Es esta la forma correcta de hacer esto? ¿Por qué el bucle foreach tiene acceso a las filas que se han etiquetado mediante el método Delete()?

+0

No necesita comprobar 'Independiente'. – SLaks

Respuesta

2

Usted tendrá que comprobar:

_dt.DefaultView.RowStateFilter 

creo que la configuración por defecto no se mostrará filas eliminadas, tal vez que se cambie alguna parte.

Siempre puede crear una RowView adicional y controlar su filtro y hacer su ciclo sobre la Vista.

+0

Eso no afectará al enumerador de la tabla. – SLaks

+0

@Slaks: escribí: 'y doblar sobre la vista' –

+0

Eso pierde las filas mecanografiadas. – SLaks

14

El Delete method marca una fila para eliminar; la fila no se elimina hasta que llame al AcceptChanges.

En su lugar, llame al _dt.Rows.Remove(_dt.FindBySomeKey(_someKey)), que también aceptará el cambio.
Lo creas o no, Rows.Remove will completely remove the row, whereas row.Delete() won't.
Tenga en cuenta que si llama al Rows.Remove, la fila desaparecerá de forma permanente y un DataAdapter no la eliminará de la base de datos.

En C# 3, puede reemplazar su estado de if con el siguiente método de extensión:

///<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()) 
{ 
    ... 

EDITAR

He aquí un C# 2 Versión:

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)) 
{ 

Usted podría también coloque esta función en la clase parcial para la tabla tipada:

partial class MyTable { 
    public IEnumerable<MyRow> CurrentRows() { return Utils.CurrentRows(this); } 
} 
+0

Gracias por la respuesta. Al hacerlo de esta manera, ¿habrá implicaciones cuando trato de actualizar mi tabla al db? _dt.Update() ¿Sabrá la Actualización() eliminar esta fila usando DeleteCommand o se habrá "ido para siempre?" – Ken

+0

@Ken: No, las filas eliminadas _no_ se eliminarán durante una actualización. Eliminar! = Eliminar –

+0

@Ken: Buen punto; Supongo que llamar eliminar hará que 'Update' no lo elimine. Intentalo. – SLaks

0

No estoy seguro de esto, pero creo que si llama al _dt.AcceptChanges() después de eliminar una o más filas, no "verá" las filas eliminadas cuando itere a través de la colección Filas de las tablas de datos.

+0

AcceptChanges elimina el estado de la fila, y necesito este estado más adelante cuando realizo una _dt.Update() para que los cambios vuelvan a la base de datos. Probablemente llamaría a AcceptChanges() después de la actualización. ¡Gracias! – Ken

1

Use GetChanges():

foreach (myDataTableRow row in _dt.GetChanges(DataRowState.Added)) 
{ 
    sbFilter.Append("'" + row.info + "',"); 
} 

Si desea obtener toda añadido y modificado, use OR bit a bit de Agregado y Modificado:

foreach (myDataTableRow row in 
    _dt.GetChanges(DataRowState.Added | DataRowState.Modified)) 
{ 
    sbFilter.Append("'" + row.info + "',"); 
} 
+1

Idea correcta, pero esto realmente produce un error de compilación porque DataTable no contiene un método público GetEnumerator(). – Ken

+0

Esto no devolverá las filas sin cambios. – SLaks

+0

@SLaks: a pesar del nombre GetChanges, puede obtener filas sin cambios, _dt.GetChanges (DataRowSate.Unchanged) –

2

Lo que está haciendo saltar las filas en su iteración es correcta, reviso rutinariamente RowState cuando recorro una DataTable que puede modificarse.

En algunos casos, creo que desea el valor de fila original antes de que la fila se marque como eliminada. Hay una opción de índice secundaria al recuperar un valor de datarow en particular.

string st = dr["columnname", DataRowVersion.Original].ToString(); // c# 

dim st As String = dr("columnname", DataRowVersion.Original).ToString() ' vb.net 

Me he atascado en este caso varias veces en el pasado.

En lo que respecta al método GetChanges (RowState), no olvide comprobar un retorno nulo, si no hay filas de ese RowState, el DataTable devuelto es nulo (creo que debería devolver una tabla con cero filas)

Cuestiones relacionadas