Tengo abandonado el blog. Ambos blogs, de hecho. El arranque tras las (cortas) vacaciones veraniegas está siendo lento. A esto hay que añadir que, en el curro, lo único que he hecho desde que he vuelto es trabajo administrativo. Ahora me toca volver con CNC (Control Numérico Computerizado) porque hay que retocar el armario para la nueva serie. Entre medias, espero sacar tiempo para terminar una aplicación a la que me queda depurarla y empezar una nueva que llevo preparando (la parte teórica y la documentación previa) desde principios del verano.
Para esta segunda conseguí sacar un ratito la semana pasada para probar el uso de marcas de tiempo y de versión para controlar la modificación de registros en la base de datos, con el fin de controlar más fácilmente los problemas de concurrencia. Tras probar varias opciones y posibilidades, lo último ha sido trabajar con el tipo de datos TIMESTAMP de SQL. No tenía pensado sacar ninguna entrada de estas pruebas pero, en fin, así parece que el blog no está abandonado y quizás a alguien le resulte útil.
Timestamp es un tipo de dato binario que puede parecer poco manejable y que genera SQL automáticamente cada vez que insertamos o modificamos una fila y nos sirve, precisamente, para controlar si se hacen cambios en las filas. Así, en la tabla tendremos una columna de este tipo. Al actualizar una fila comprobaremos primero si su valor de control timestamp con el que nosotros tenemos. Si no es igual, es que alguien ha cambiado esa fila desde que nosotros accedimos a ella.
En Visual Basic, al generar un dataset tipado, el tipo timestamp nos lo presenta como un array de Bytes. Las consultas de inserción y modificación generadas en el TableAdapter incluyen un Select que devuelve la fila insertada o modificada, para obtener su valor timestamp correcto, ya que el valor lo genera SQL automáticamente. Cuando mandemos una fila modificada de vuelta a la base de datos, se comprobará que el timestamp de la fila que hay en la base de datos coincide con el de la datarow original. Si no coincide, se producirá un error de concurrencia que gestionaremos como mejor nos parezca.
Además de su utilidad para el control de concurrencia, me puse a enredar con este tipo de valor para darle otros usos.
Por ejemplo, puede ocurrir que tengamos una tabla en memoria y queramos comprobar si se han producido cambios desde que la cargamos. En la carga de datos podíamos guardarnos el valor más alto del timestamp de esa tabla (SELECT MAX(MiColumnaDeControl) FROM …) y luego, cuando queramos comprobar si hay cambios, preguntar a la base de datos si hay registros con un timestamp más alto (… WHERE MiColumnaDeControl > @MiOldTimestamp) en esa tabla. En caso de que haya nuevos registros, podríamos recargar la tabla, o traernos únicamente los registros nuevos o modificados en un dataset auxiliar y luego unirlo al principal mediante el método Merge. El problema de esto es que si, en lugar de registros nuevos o modificados, hablamos de registros eliminados, pues no nos serviría. Aunque, viendo las aplicaciones comerciales que tengo en el trabajo, tampoco es tan grave, la verdad.
Lo anterior es sin tocar los datos recuperados de la base de datos, es decir, teniendo el timestamp almacenado en un array de Bytes y santas pascuas. Sin embargo, podría querer comparar los valores timestamp de registros que ya tenga en memoria (no sé para qué, como digo sólo estaba trasteando un viernes por la tarde). Con un array de Bytes no sé muy bien qué hacer, pero puedo convertirlo en una cadena de caracteres hexadecimales. El código viene de ejemplo en la propia documentación de Visual Studio en la entrada de Byte (estructura). Esta cadena hexadecimal la puedo convertir luego en un número decimal usando Convert. Por ejemplo, Convert.ToInt64(MiCadena, 16).
Si uso LINQ to SQL, tres cuartos de lo mismo, sólo que el tipo de dato de LINQ es binario. Tiene un método para convertirlo en array de Bytes y ya estamos igual.
En fin, lo que uno hace cuando se aburre en el trabajo y empieza a probar cosas que no conocía. A ver si la semana que viene hago algo más útil que me dé para hacer una entrada medianamente interesante y no esto.
Pingback: Quemando Cromo » Blog Archive » Trasteando en un dataset: seguimos jugando con valores timestamp