PDA

Ver la Versión Completa : Transacciones + ventanas MDI


rafadrover
18-08-2003, 14:57:33
Tengo un pequeño problema y agradeceria unas sugerencias, el problema es el siguiente, las transacciones y las ventanas MDI, por ejemplo tengo una ventana MDI fichaCliente, como la base de datos es interbase, tengo una transaccion activa, el usuario modifica datos el la tabla cliente, ahora abren la ventana facturacion, tambien MDI, me hacen una factura y al final me hacen un commit, con este commit se han guardado los datos de factura y de cliente, pero si hacen un rollback, pierdo los datos de cliente. Solucion, hacer un commit cuando se habre la ventana factura, o bien cuando pierde el foco la ventana cliente.
Todo esto es porque no trobajo en cachedUpdates y cuando le pido al usuario aplicar cambios cliente S/N, hago un commit o rallback (Es un poco heavy), que me sugeris, que cambie a cachedupdates o sabeis algun sistema mejor.

Gracias a todos.

__cadetill
18-08-2003, 15:15:40
Te explico como yo lo hago

Las ventanas MDI sólo las utilizo para la visualización de datos en un Grid y hacer busquedas y cosas por el estilo, pero cuando tengo que modificar o añadir un registro, muestro una ventana modal con DBEdits (o lo que sea) y, al aceptarla es cuando hago el Commit de la transaccion (o el Rollback si la cancelan)

En tu caso podria mirar de hacer un Commit al aceptar (post) un registro.

Son sólo ideas ;)

Voutarks
18-08-2003, 16:13:40
La solución está simplemente en utilizar transacciones distintas para cada proceso. En un mismo programa se puede uyilizar perfectamente varias transacciones.

Si nos damos cuenta ambas operaciones no son una sola, es decir, no están directamente relacionadas, por lo tanto, lógicamente son dos procesos distintos y dos transacciones distintas. No tiene sentido que sean una sola.

Voutarks
18-08-2003, 18:31:58
Bueno, en el post anterior hablaba de la situación más logica. A ver cómo se hace eso con Delphi. Puse que era fácil utilizar varias transacciones porque ahora uso los componentes IbObjects y con ellos se pueden asignar varios objetos 'Transaction' a un solo 'Connection' y luego decir a cada grupo de sentencias SQL que transacción utilizan, con lo que ya está todo solucionado. No todo el muno usa estos componentes, asi que perdón por el lapsus. :D

Con los componentes estándar de Delphi: para utilizar varias transacciones podríamos crear dinámicamente componentes de acceso a datos y manejarlos así, sobre la marcha, aunque la programación de esto es algo complicada. Es decir, crear un 'Transaction', un 'Connection', un 'Query', etc para cada ventana que se abra con lo que sería como si el usuario ubiese ejecutado la aplicación otra vez. Una opción que nadie usaría sería tener varios juegos de componentes de acceso a datos, uno para cada ventana MDI que se pueda abrir... pero ya digo, ni lo pienses.

Bien eso era para utilizar varias transacciones, pero ahora te voy a decir lo que yo haría, en tu caso:
Supongo que se te pierden los datos del otro formulario porque utilizas controles enlazados a datos. Personalmente no me gusta utiliazr estos controles, únicamente algún que otro DbGrid, y de solo lectura, donde es necesario (aunque yo he llegado a utilizar un StringGrid que 'cargo' tras una consulta SQL). Lo perfecto para ti serían controles normales, los cuales 'cargas' de datos.

Por pasos: Al abrirse un formulario abres la transacción, haces una o varias consultas para traer los datos, cierras la transacción. Después de que el usuario ha insertado o modificado los datos en el formulario y le da a un botón de aceptar entonces abres la transación, mandas los datos con un INSERT o UPDATE y cierras la transacción inmediatamente.

Así no queda la transacción abierta en ningún momento y no hay ningún problema con que el usuario maneje varios formularios a un tiempo. Si tienes, por ejemplo, algún control DbLookupComboBox, pon un simple Combobox y con una pequeña instrucción SQL 'cargas' la lista desplegable con los datos que interesan. Luego, al enviar la sentencia de inserción o modicicaión, primero lo compruebas para enviar el valor correcto.

Como ves, todo esto lleva más programación, pero los resultados lo merecen.

rafadrover
18-08-2003, 18:34:28
El problema que le veo tener una transaccion por ventana de entrada de datos es el siguiente, supongamos que la tabla cliente esta asignada a una transaccion, y la tabla factura a otra, creo un cliente desde una ventana MDI hago un commit, luego voy a la ventana factura, busco el cliente y este no esta, tengo que cerrar y abrir la tabla clientePorFactura para que se me reflejen los cambios. Creo. De todas maneras no lo he probado en serio, quizas me lo tendria que replantear.
Gracias.

La solucion de mantener un Grid en modo solo lectura tambien es possible, pero no es tan elegante, creo yo, no se.:p

kinobi
18-08-2003, 18:43:19
Hola,

Posteado originalmente por Voutarks
En un mismo programa se puede uyilizar perfectamente varias transacciones.

Si bien es completamente cierta la frase anterior, también lo es que con determinados mecanismos de acceso, p. ej. BDE, la forma de conseguirlo dista mucho de ser la mejor, ya que, en el caso concreto del BDE, cada sesión (conexión) está asociada a una (y solo una) transacción. Es decir, para tener n transacciones diferentes, hay que tener abiertas n sesiones (conexiones) diferentes. Evidentemente, con mecanismos de acceso como IBX, IBO, ..., sí se pueden tener varias transacciones bajo la misma conexión, pero el compañero que inició el hilo no especifica que mecanismo utiliza.

Saludos.

kinobi
18-08-2003, 18:45:06
Hola,

bueno, parece que mientras escribía mi mensaje anterior ya habéis comentado el asunto.

Saludos.

Voutarks
18-08-2003, 18:48:02
Justo, por eso te dije la opción de los controles normales y todo lo demás. Así no tendrías ese problema.

De todas maneras es algo lioso como te he contado tener en el mismo formulario, junto con los controles descritos antes, un grid.

rafadrover
19-08-2003, 08:33:07
Voy a liar un poco mas la cosa:
Supongamos que tenemos una ficha MDI cliente, y otra ficha MDI reserva, en la de cliente se inicia un transaccion, y al final un commit. En la de reserva igual. Desde la ficha de reserva se puede abrir la ficha de cliente, en forma modal, por tanto, cuando se tiene activa transaccion de reserva, se inicia otra, la de cliente, si ambas tablas tienen asociadas la misma transaccion, cuando se cierra la ventana cliente, esta hace el commit, guardando todos los datos de reserva, luego volvemos a la ficha de reserva, si hacemos un commit, todo va bien, pero si el usuario quiere cancelar el trabajo y son transacciones distintas, todas las operaciones de reserva, se cancelan, pero las de cliente al ser una transaccion distinta se han guardado. Que hacemos en estos casos? Modificar dinamicamente la transaccion de la tabla cliente?

kinobi
19-08-2003, 08:59:03
Hola,

Posteado originalmente por rafadrover Voy a liar un poco mas la cosa:
Supongamos que tenemos una ficha MDI cliente, y otra ficha MDI reserva, en la de cliente se inicia un transaccion, y al final un commit. En la de reserva igual.
Si he entendido bien, hay dos transacciones, una en cliente y otra en reserva.

Posteado originalmente por rafadrover Desde la ficha de reserva se puede abrir la ficha de cliente, en forma modal, por tanto, cuando se tiene activa transaccion de reserva, se inicia otra, la de cliente, si ambas tablas tienen asociadas la misma transaccion,
Imposible. Si se inician dos transacciones, son dos transacciones. No hay forma de ligar una transacción a la otra. Además, una de las características de cualquier sistema transaccional es el aislamiento entre transacciones.

Posteado originalmente por rafadrover cuando se cierra la ventana cliente, esta hace el commit, guardando todos los datos de reserva,
Entiendo que es guardar los datos de reserva sin hacer commit.

Posteado originalmente por rafadrover luego volvemos a la ficha de reserva, si hacemos un commit,
Correcto, ahora hacemos el commit en reserva.

Posteado originalmente por rafadrover todo va bien, pero si el usuario quiere cancelar el trabajo y son transacciones distintas,todas las operaciones de reserva, se cancelan, pero las de cliente al ser una transaccion distinta se han guardado.
Si se ha hecho el commit en ambas transacciones (cliente y reserva) no hay forma de volver atrás (no al menos directamente), ni en una ni en otra. Además, debido a lo que comentamos anteriormente del aislamiento entre transacciones, lo que haya ocurrido con la transacción en cliente no afecta a lo que vaya a ocurrir con la transacción reserva. Entiende "no afecta" desde el punto de vista del mecanismo de confirmación (commit) o rechazo (rollback) de los cambios, otra cosa es que un cambio en los datos de una transacción pueda hacer que el servidor no acepte los cambios de otra debido a restricciones de integridad.

Saludos.

Voutarks
19-08-2003, 09:32:15
A ver si lo entiendo, tienes un primer formulario que se abre y desde este se puede abrir un segundo formulario.

Lo que quieres entonces es que si después de que el usuario ha aceptado los cambios en el segundo formulario, si le da al botón cancelar en el primer formulario se deshagan los cambios que hizo en ese segundo formulario. Y también quieres dejar la opción, como comentaste al principio de este hilo, de que si el usuario modifica datos en el primer formulario, luego abre el segundo y cancela los cambios en el segundo form. se mantenga lo que escribió en el primero ¿correcto?

Pues entonces efectivamente tienes que utilizar dos transacciones y no tienes que hacer el commit de la transacción del segundo formulario cuando se le da al botón aceptar de este formulario, sino:

En el segundo formulario:
-> En el botón cancelar, haces un rollback de la segunda transacción.
-> En el botón aceptar simplemente cierras el formulario, sin más.

En el primer formulario:
-> En el botón cancelar, primero miras si la segunda transacción está activa y si es así haces un rollback de la segunda. Después un rollback de la primera.
-> En el botón aceptar, primero miras si la segunda trans. está activa y si es así haces un commit de esta. Finalmente haces un commit de la primera.

Lo malo es que desde el primer formulario no se van a poder ver los cambios que se hacen con el segundo, si es que tienen que verse. Si es necesario que sea así entonces podrías utilizar sólo una transacción pero tendrías que guardar los valores del registro o registros que modifica el segundo en algún lado, como en una matriz y luego si el usuario cancela en el primer form coger los datos de ahí y deshacer el cambio con una instruccion UPDATE. Además tendrías que hacer lo que dije en un mensaje anterior, lo de cargar los controles y cerrar la transacción y todo eso.