PDA

Ver la Versión Completa : Problemas al actualizar con upWhereChanged(dbExpress)


ibarrols
30-06-2003, 15:10:59
Hola foro !!

Estoy trabajando con DbExpress y D7.

He estado leyendo sobre las distintas modos de actualizar registros del
cliente a la base (modeUpdate: upWhereAll, upWhereKeyOnly y upWhereChanged.
Según lo que leí en
http://www.marteens.com/trick4e.htm, el que más se recomienda es el
upWhereChanged.
Mi problema está en que no logro actulizar mi base al hacerlo de esta
manera, es más, la única que me funciona es cuando uso el modo upWhereAll.
Tengo una tabla 'pais' y quiero actualizar un solo registro.
Para eso tengo:
1. SQLDataSet (SELECT * FROM pais WHERE idPais = :idPais), que le llame
qPais.
2. DataSetProvider
3. ClientDataSet, que le llamé cPais
4. DataSource

El código consiste en 3 botones con el siguiente contenido:

Un botón que lee el registro de la tabla 'pais':
qPais.ParamByName('idPais').value := 1; // es la clave principal
primaria y unica
qPais.Refresh;
cPais.Open;

Un botón para modificar el registro leido:
cPais.Edit;
cPais.FieldByName('nombre').Value := 'xxxxxx';
cPais.Post;

Y un botón final para grabar en la base los cambios:
cPais.ApplyUpdates(0);



Cuando utilizo el upWhereChanged me sale el siguiente error:
'Update affected more than 1 record'

Cuando utilizo el upWhereKeyOnly me sale el siguiente error:
'Unable to find record. No key specified'


Les agradeceré que me puedan orientar en este problema que tengo.

guillotmarc
30-06-2003, 22:12:55
Hola.

El problema con el modo upWhereKeyOnly, está en que tienes que modificar la propiedad ProviderFlags, del campo persistente correspondiente al campo de clave primaria, en el SQLDataSet (no en el ClientDataSet), y añadir la opción de pfInKey.

Olvídate del modo upWhereAll, cuando la consulta se base en una unión de tablas, no podrás usarlo.

Sobre el problema con el modo upWhereChanged, te está indicando que va a modificar más de un registro. Aunque como no uso ese modo, no te puedo indicar el modo correcto de utilizarlo.

Saludos.

ibarrols
30-06-2003, 23:28:45
Marc:
Gracias !!! Problema solucionado !!
Cuando se usa la opcion de upWhereChanged tambien hay que incluirle al Provider Flags el pfInKey en true, de igual modo que en upWhereKeyOnly.

Por lo que lei la opcion mas recomendada es upWhereChanged y no upWhereKeyOnly. Como no tengo experiencia en este tema, me gustaria saber porque es que vos acostumbras usar upWhereKeyOnly.


Desde ya gracias por tu apoyo

guillotmarc
02-07-2003, 15:20:43
Hola.

No la utilizo porque sea mejor, simplemente lo hago porqué me comporta menos trabajo.

Con la opción upWhereChanged, para localizar el registro a modificar, se busca en función de la clave primaria y los campos a modificar. De esta forma, si uno de los campos a modificar, no tiene el mismo valor que tenía al principio, no se puede encontrar el registro, y salta un error indicando que otro usuario ha modificado ese registro sin que nos dieramos cuenta.

Esto no es problema en mi caso, pero si quieres que tu aplicación se de cuenta de que otro usuario ya ha modificado el registro que tu estás modificando, entonces tendrás que utilizar el upWhereChanged.

Naturalmente conlleva más trabajo, puesto que hay que decidir que hacemos, ¿ cancelamos la modificación que se intenta hacer ?, ¿ mostramos los campos que queremos modificar, y los valores que ha entrado el otro usuario, para poder decidir cuales mantenemos ?, .....

En cambio con el modo upWhereKeyOnly, localizamos el registro por su clave primaria. De esta forma nunca nos damos cuenta de si otro usuario ha modificado el mismo registro, y no salta ningún error.

La utilización de uno u otro modo, la tienes que hacer en función de si quieres detectar los conflictos de actualización entre usuarios o no.

Saludos.

Gisela
10-07-2003, 21:31:24
Hola.
He leído lo que estuvieron discutiendo y quisiera comentarles mi problema.
Estoy trabajando con dbExpress (sqlDataSet, ProviderDataSet, ClientDataSet) y realizo una actualización sobre un campo que pertenece a la clave primaria, al momento de ejecutar el applyUpdates del clientDataSet sale el siguiente error:

'Record not found or changed by another user'

Probé con los tres modos de actualización del provider, además en el providerFlags del sqlDataSet indiqué los campos que pertenecen a la clave primaria y siempre sale el mismo mensaje de error.

¿Con ClientDataSet no se puede cambiar el valor de un campo perteneciente a la clave primaria? ¿Alguien tiene idea de qué estoy haciendo mal?

Muchas gracias!!
Gisela

guillotmarc
10-07-2003, 21:54:57
Hola.

Nunca se me ha ocurrido probarlo, pero ciertamente es muy probable que no te deje hacerlo, puesto que después es incapaz de localizar ese registro para actualizarlo. (además ese es justamente el error que te da, que no puede localizar el registro a modificar).

¿ Realmente necesitas cambiar la clave primaria ?. ¿ Estás segura que deseas permitirlo ?

Las claves primarias sirven para identificar de forma única los registros, y las utilizamos para establecer relaciones. Si alguien cambia una clave primaria, todas las tablas relacionadas dejarán de tener una referencia válida. (Cosa que te obliga a definir costosas relaciones de integridad con actualizaciones en cascada)

¿ No sería mejor añadir un campo autonumérico para la clave primaria, y los campos que actualmente tienen la clave primaria ponerlos en un índice único para asegurarse que no se duplican ?

Las relaciones entre tablas, se harían entonces apuntando al campo autonumérico. Y podrías cambiar libremente, sin los problemas que tienes actualmente, los tres campos que antes formaban la clave primaria.

Saludos.

Gisela
10-07-2003, 22:47:54
Entiendo lo que me decís. En la mayoría de mis tablas tengo claves únicas, pero hay otras que las relacionan y en lugar de crearle una clave unica, he usado las claves externas para formar la clave primaria. Es decir, fué una decisión que podría estar mal. Lo que no sé es si podría modificar el valor de uno de los campos de la clave primaria usando un ClientDataSet tal cual como lo puedo hacer ejecutando un sql desde la consola de la base de datos (UPDATE xx SET clave2=8 WHERE clave2=3 AND ... ... ... ). ¿Considerás incorrecto usar claves externas para formar una clave primaria o solo te parece mal que intente modificar la clave? Por ejemplo: tengo una tabla de alumnos y una de carreras, cada una con una clave primaria simple. En otra tabla guardo todas las carreras que curse cada alumno con atributos propios de esa relación. Yo pondría como clave primaria de esta tabla el codAlumno y el codCarrera. Si quisiera modificar el código de la carrera estaría modificando la clave primaria ...
Me gustaría saber tu opinión

Gracias!!
Gisela

guillotmarc
11-07-2003, 00:04:29
Hola.

Todo es cuestión de gustos, no digo que sea incorrecto lo que estás haciendo. Recuerdo haber visto tablas de Access con claves primarias formadas por más de 5 campos, y como tu caso, esos campos eran a la vez claves externas para relaciones entre tablas.

Pero a mi me gusta que la clave primaria sea un unico campo entero (autoincremental, no seleccionado por el usuario). Creo que esto facilita la definición de las relaciones de integridad.

Supón que a la tabla Carreras_Alumno, le quieres relacionar una tabla Examenes (para cada carrera un Alumno puede cursar más de un examen). Entonces en la tabla Examenes tendrás que guardar los campos Carrera, Alumno, añadiendo un campo Fecha para hacer una clave primaria formada por esos 3 campos.

¿ Que pasa si se cambia un código de la tabla Carreras ? Tienes que arrastrar ese cambio a la tabla Carreras_Alumno y Examenes. O más probable aún, como quieres poder hacer, si cambias el campo Carrera o Alumno en Carreras_Alumno entonces tienes que arrastrar el cambio a los registros relacionados de la tabla Examenes.

En cambio si cada tabla tiene su campo Entero como clave primaria, las relaciones són por ese campo. Entonces puedes cambiar tranquilamente un código de la tabla Carreras, o la Carrera o Alumno de un registro de Carreras_Alumnos, que no afecta para nada la validez de las tablas relacionadas.

Además las tablas tendrán menos campos y será más rápido y sencillo de definir las relaciones. (y no tendrás el problema con dbExpress, con el que sospecho que no podrás cambiar los valores de un campo de clave primaria).

NOTA : Si te interesa asegurar que en la tabla Carreras_Alumno se tengan que especificar los campos Carrera y Alumno, además de que no se puedan duplicar dos registros con los mismos valores de Carrera y Alumno, solo tienes que definir esos campos como no nulos, y añadir un índice único a la tabla, formado por los dos campos.

Es solo una opinión (la forma que yo uso), pero espero que te sea de ayuda.

Saludos.

Gisela
11-07-2003, 15:16:37
Hola. Gracias por tu opinión, Marc. Sin dudas ha sido de ayuda.
Todavía no me convenzo de cambiar la estructura de la base de datos solo porque se me complique resolver esta modificación en Delphi, pero lo que si he estado pensando es que tenés razón en cuanto a la transparencia y sencillez que se logra. Usando claves compuestas se vuelve más engorroso definir las validaciones de integridad entre tablas ya que hay que arrastrar con TODOS esos campos ...

Estamos considerando crear claves con un único campo para simplificar el modo en que trabajamos.

Gracias de nuevo!
Gisela