Como es bien sabido la clase DataSet de .NET (dentro del espacio de nombres System.Data), permite utilizar de manera sencilla y potente un pequeño gestor de datos en memoria, sin necesidad de haber obtenido por fuerza los datos a partir de un gestor de datos convencional. El objeto DataSet puede haber sido creado dinámicamente por nosotros o se puede haber generado para trabajar en memoria con tablas y relaciones obtenidos de una fuente de datos relacional, por ejemplo.

Un DataSet contiene, entre otras cosas, una colección de objetos DataTable que, como puede imaginar, son equivalentes conceptualmente a las tablas o relaciones en una base de datos relacional. No voy a entrar aquí a explicar todas las características de este tipo de objetos, pero sí me gustaría recordar que generan dos eventos con el fin de notificar de los cambios que sufren. Estos eventos son RowChanged y RowDeleted, y se lanzan cuando se cambia algún valor  o cuando se elimina una fila de la tabla respectivamente.

Aprovechando esta coyuntura es bastante fácil construir una clase que se ocupe de registrar automáticamente todos los cambios que se realicen sobre una tabla en memoria (DataTable). Basta con almacenarlos en una pila y mediante un método 'Undo' o similar ir deshaciéndolos uno a uno hasta dejarla como estaba en el momento en que nuestra clase comenzó a controlar sus cambios. Esto contrasta por ejemplo con el uso del método RejectChanges del DataTable, que deshace todos los cambios sufridos por la tabla, pero no permite dejarla en un punto intermedio.

En este enlace he dejado un archivo (10 KB) con el código fuente completo en C# y la DLL ya compilada de una clase llamada DataTableLogger que consigue precisamente esto que he descrito: controla de forma automática todos los cambios que sufre un DataTable que se le pase en su constructor, permitiendo posteriormente ir deshaciéndolos desde el final a través de un método Undo.

Así, para comenzar a controlar los cambios sufridos por una tabla sólo habría que escribir:

DataTableLogger DLogger = new DataTableLogger(DataTableAControlar);

Si luego quisiésemos deshacer el último cambio sufrido sólo habría que escribir:

DLogger.Undo();

que además devuelve el número de cambios que quedan por deshacer. Existe también una propiedad llamada ChangesCount que indica este mismo valor pero sin necesidad de llamar a Undo. Con este valor (obtenido mediante cualquiera de las dos formas) se puede escribir fácilmente un bucle que deshaga todos los cambios, uno a uno.

La clase se puede heredar para aprovechar su funcionalidad en otras clases más potentes que permitan controlar, por ejemplo, un DataSet completo, guardando los cambios de todas las tablas que éste contenga, aunque esto se deja como ejercicio para el lector ;-)

OJO: hay una pequeña pega con esta clase. Si una determinada fila sufre dos cambios diferentes, cuando se llame al método Undo para restablecer el último, en realidad como podrás comprobar en el código, se estarán restableciendo todos a la vez (el segundo y el primero). Eso es porque se usa el método RejectChanges de la fila que la restablece a su valor original cuando se llama. Es relativamente sencillo (aunque tedioso) ampliar el código de la clase para que tenga en cuenta esta eventualidad. Bastaría con interceptar el evento ColumChanged de la tabla y almacenar el valor orginal del campo que se cambia junto con la referencia a la fila dentro de la pila de deshacer de la clase.
Si alguien lo implementa por su cuenta o incluso alguien crea una clase similar para controlar un DataSet completo le agradeceré que me haga llegar el código ampliado.

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor