FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
|||
|
|||
TClientDataSet.applyupdates (error: record not found or changed by another user)
Hola a todos, de nuevo aquí me encuentro con un error que me está volviendo loco, llevo varios días con esto.
Se trata del error que da el programa ha ejecutar la sentencia: clientdataset.applyupdates error: record not found or changed by another user. (Trabajo con Firebird 2.1.1 y Borland Studio 2005) Uso los componentes de Interbase para conexión a BBDD, siempre sin problemas. Las sentencias son las habituales, como puede verse:
Esto es lo habitual, aunque he aislado el código, en el programa todo es más complejo, no sé... he probado a ejecutar varias máquinas, no hay problema de permisos etc. Con el IB_Expert puedo modificar bien. Ni idea... ¿Alguien tiene alguna idea? Muchas gracias por vuestra ayuda. |
#2
|
||||
|
||||
Para eliminar o actualizar el registro, el componente proveedor necesita identificarlo de algún modo. Normalmente es mediante el campo que tenga la bandera pfInKey en ProviderFlags. Pero eso depende de qué valor tenga la propiedad UpdateMode del proveedor. Por lo general se recomienda upWhereKeyOnly.
En DBConsts.pas se encuentra la constante: SRecordChanged = 'Record not found or changed by another user'; la cual es usada en varios puntos de la unidad Provider.pas Si compilas el programa con la opción Use Debug DCUs (del cuadro de diálogo Project Options), a la hora de saltar una excepción el IDE te proporcionará más información sobre qué camino siguió el programa hasta llegar a la condición de error. Usando la pila de llamadas (Ctrl+Alt+S) podrás ver, en este caso, en qué punto de la unidad Provider no se cumplió alguna condición necesaria para la correcta aplicación de cambios. Te sugiero revisar las propiedades ProviderFlags y UpdateMode. Saludos. Al González. Última edición por Al González fecha: 11-03-2009 a las 17:25:09. Razón: Cambiar "Para eliminar..." por "Para eliminar o actualizar..." |
#3
|
|||
|
|||
Buenas,
Al Gónzalez ¡cuánto honor! que seas quien trate de guiarme entre este mar de sombras. Cita:
Bien, ahora paso a intentar dar más información porque no soy capaz de aclararme viendo el debug de todo lo que me has recomendado. Esto es lo que veo: En la unit DBClient ejecutando el método 'TCustomClientDataSet.GetDelta', en la última línea 'DataPacketToVariant(TempPacket, Result);' Tras ejecutarla y ponerse sobre el 'end', llama posteriormente a una serie de código ensamblador en la unit 'System', tras lo cual es dónde se muestra la excepción. Creo entender que el código ensamblador ese es lo que lanza la expceción, pero no puedo sacar nada en claro. La líneas de ensamblador que comento. Unit 'System':
¿Podemos avanzar con esta nueva información? Un saludo y gracias por la ayuda. |
#4
|
||||
|
||||
Quise decir eliminar o actualizar. En ambos casos es necesario que el proveedor identifique al registro en cuestión mediante uno o varios campos. Normalmente es por el campo de llave primaria cuando UpdateMode es upWhereKeyOnly, pero siempre y cuando dicho campo tenga la bandera pfInKey. ¿Ya revisaste la propiedad ProviderFlags de ese campo en ambos conjuntos de datos?
Respecto al depurador, cuando ocurra la excepción abre la ventana Call Stack (pila de llamadas) la cual te mostrará cómo fueron ejecutándose las rutinas una tras otra hasta llegar al punto de la excepción. El elemento superior de esa lista es la rutina más actual o reciente (donde ahora está detenido el programa, vaya), la cual fue llamada por la segunda de la lista, y ésta a su vez por la tercera, etc. Dando doble clic sobre alguna de ellas, te mostrará el punto exacto del código fuente donde esa rutina llamó a la que le sigue arriba. En alguna de las primeras, es muy probable que encuentres una sentencia como: . Con eso también puede indagarse qué validación no se cumplió en TDataSetProvider o alguna otra clase asociada, para que la excepción SRecordChanged fuera lanzada. Espero haber aclarado un poco el asunto, por favor indícanos tus dudas y avances. Saludos. Al. |
#5
|
|||
|
|||
Buenas de nuevo.
Cita:
TDataSet-> FFields -> FDataSet -> FFields etc. no hay manera de ver mi lista de campos. Por otra parte he visto usando el depurador detenidamente que al ejecutar el siguiente método del provider:
Ejecuta la línea -> RowsAffected := PS2.PSExecuteStatement(SQL.Text, Params) Y RowsAffected queda con valor '0' tras ello, y por tanto es lo que hace que se lance la excepción (en la última línea del procedimiento) No sé, tendrá que ser una tonteria (ni idea). Creo que sería más fácil aislar el codigo y dejártelo ver o ejecutar a ver que opinas. Gracias de nuevo. |
#6
|
|||
|
|||
Bien, he puesto un bucle para recorrer los campos del ClientDataSet y mirar sus propiedades.
De esta manera he visto que el campo 'ID' tiene como ProviderFlags: [pfInUpdate..pfInKey] Y el resto de campos (estando todos ok con sus valores obtenidos): [pfInUpdate..pfInWhere] No sé esto podrá ayudar... |
#7
|
||||
|
||||
Cita:
En cuanto a las banderas del campo ID, parecen estar bien. La clave va a estar en esa sentencia SQL Update (SQL.Text) que no afecta a la base de datos, probablemente porque los parámetros indican un registro inexistente. Esperamos retroalimentación. Al González. |
#8
|
|||
|
|||
Buenas de nuevo, allá vamos. Primero respondo, y luego agrego
Con el Debug detenido justo antes de la sentencia que lanza la excepción 'DatabaseError(SRecordChanged);'. Ello en el método y unit: procedure TSQLResolver.DoExecSQL(SQL: TWideStringList; Params: TParams); He mirado el contenido de SQL.Text, sólo pidiendolo sobre el código porque sobre el inspector de objetos 'local variables', el depurador no mostraba tal propiedad. Este es su contenido, tras haber añadido informacion a cada campo directamente, para acotar el error más a fondo:
Y Esta es la query realizada, que inicialmente obtiene los datos del cliente para mostrarlos en el formulario:
Ahora viene lo mejor, ayer estuve haciendo un programa de prueba para aislar la funcionalidad que puede ocasionar el problema. Cree una tabla cliente con tres campos (ID,Nombre,Direccion) añadi las clases implicadas, y... ¡voila! funcionaba perfectamente. ¿Qué puedo hacer? pues seguramente alguna parte del programa está afectando, pero mira que llevo horas depurando, no hay queries que 'intoxiquen' al provider, ni nada que yo haya visto que pueda afectar. Lo único que se me ocurre es ir añadiendo código a mi programa de prueba hasta que ocurra el mismo error que ahora se da en el programa completo. ¿Alguna idea más? Gracias y un saludo. |
#9
|
||||
|
||||
¡Hola!
Excelente dato. No sé si ya notaste que esa sentencia "Update Cliente..." no está usando upWhereKeyOnly, sino que pareciera usar upWhereAll. Cita:
En teoría, si UpdateMode fuese upWhereKeyOnly, ese "Update Cliente..." debería terminar en un simple "Where ID = ?", y no incluir a todos los demás campos en la cláusula Where. Funcionando entonces correctamente. Nuevamente, al estar detenido el programa en ese punto, revisa qué valor tiene la propiedad Provider.UpdateMode. No con el inspector, sino metiendo "Provider.UpdateMode" a las observaciones (watches). Todo parece indicar que NO es upWhereKeyOnly, sino upWhereAll. ¿Alguna parte del programa estará cambiando esa propiedad? Esperamos tus avances. Al González. Última edición por Al González fecha: 13-03-2009 a las 18:21:09. |
#10
|
|||
|
|||
Hola de nuevo,
lamento la tardanza en responder, resulta que he estado estudiando bien en el tema. Y tienes razón, se colaba en un sitio no esperado el cambio de la propiedad Provider.UpdateMode a upWhereAll. Cuanto siento el tiempo que hemos perdido por algo que no era tan complicado en realidad. Después de 'arreglar' este error he seguido con problemas asociados pues el provider era usado por otras queries (en algunos casos del programa) y perdía la referencia del registro del DataSet original. Quizá por simplificar (usar un Provider que se alimenta de varias queries) he terminado complicando más el tema. Bueno, muchas gracias de nuevo por tu valiosa ayuda. Volveremos a vernos pronto, seguro. Saludos. |
#11
|
||||
|
||||
Cita:
Puede que valga la pena abrir un hilo sobre esa cuestión particular. |
#12
|
|||
|
|||
Bien, entonces quizá lo mejor es que cuando tenga listo y depurado el tema haga una exposición de cómo he organizado la distribución de Queries+Providers+DataSet y discutamos ¿cierto?.
Esta organización la estoy usando en una clase genérica que he creado, la cual define un comportamiento bastante común: sacar listados de esa entidad, obtener datos de ficha, actualizar, etc. Y clases que siempre suelen funcionar igual como 'clientes', 'contactos', 'proveedores' etc la heredan. Gracias y un saludo. |
|
|
Temas Similares | ||||
Tema | Autor | Foro | Respuestas | Último mensaje |
applyupdates (record not found or changed by another user) | Stell | Conexión con bases de datos | 4 | 13-05-2008 13:36:20 |
Error: "Record not found or changed by another user" | jmlifi | Varios | 0 | 27-01-2006 10:16:57 |
Record not found or changed by another user | felixgo | Conexión con bases de datos | 1 | 30-09-2005 13:07:40 |
Record not found or changed by another user. | Luis | Conexión con bases de datos | 2 | 12-08-2005 19:50:45 |
error couldn't perform the edit because another user changed the record | marcelofabiani | Conexión con bases de datos | 3 | 25-01-2005 01:55:11 |
|