Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Conexión con bases de datos
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Conexión con bases de datos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 10-03-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Unhappy 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:
Código Delphi [-]
// cds es el ClientDataSet
// 1. Ponemos en modo de edición
cds.Refresh(); // aunque es prescindible
cds.Edit();
// 2. Modificamos algunos campos
cds.FieldByName('Campo1').AsString := 'valor1';
// 3. Actualiza el registro en curso
cds.Post();
// 4. Hacemos efectivos los cambios
if cds.ApplyUpdates(0) <> 0 then
    raise Exception.Create('error grabando');
self.transaction.Commit;

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.
Responder Con Cita
  #2  
Antiguo 10-03-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
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..."
Responder Con Cita
  #3  
Antiguo 11-03-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Buenas,
Al Gónzalez ¡cuánto honor! que seas quien trate de guiarme entre este mar de sombras.

Cita:
Empezado por Al González Ver Mensaje
Para eliminar 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.
No sé a que te refieres con eliminar. Solamente he obtenido un registro de la tabla 'clientes' y muestro sus datos en el formulario con controles 'data-aware'. El error me sale al editar. La consulta no cruza tablas, y la propiedad en el provider (TDataSetProvider) está UpdateMode=upWhereKeyOnly y creo que no debe dar problemas, ¿cierto?

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':
Código Delphi [-]
function _IntfClear(var Dest: IInterface): Pointer;
{$IFDEF PUREPASCAL}
var
  P: Pointer;
begin
  Result := @Dest;
  if Dest <> nil then
  begin
    P := Pointer(Dest);
    Pointer(Dest) := nil;
    IInterface(P)._Release;
  end;
end;
{$ELSE}
asm
        MOV     EDX,[EAX]
        TEST    EDX,EDX
        JE      @@1
        MOV     DWORD PTR [EAX],0
        PUSH    EAX
        PUSH    EDX
        MOV     EAX,[EDX]
        CALL    DWORD PTR [EAX] + VMTOFFSET IInterface._Release
        POP     EAX
@@1:
end;

¿Podemos avanzar con esta nueva información?
Un saludo y gracias por la ayuda.
Responder Con Cita
  #4  
Antiguo 12-03-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por Bauhaus1975 Ver Mensaje
No sé a que te refieres con eliminar
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:
Código Delphi [-]
DatabaseError(SRecordChanged);
.

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.
Responder Con Cita
  #5  
Antiguo 12-03-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Buenas de nuevo.

Cita:
Empezado por Al González Ver Mensaje
¿Ya revisaste la propiedad ProviderFlags de ese campo en ambos conjuntos de datos?
Creo que te refieres a ver la propiedad del TField 'ID' que es la clave de la tabla. Pero no puedo (o sé) ver la lista de campos. Cuando va a realizar el cds.Applyupdates, trato de ver los campos del clientdataset (bajo el objeto TDataSet), pero son listas que muestran una direccion de memoria.
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:
Código Delphi [-]
procedure TSQLResolver.DoExecSQL(SQL: TWideStringList; Params: TParams);
var
  RowsAffected: Integer;
  PS2: IProviderSupport2;
begin
  if Supports(Provider.DataSet, IProviderSupport2, PS2) then
    RowsAffected := PS2.PSExecuteStatement(SQL.Text, Params)
  else
    RowsAffected := (Provider.DataSet as IProviderSupport).PSExecuteStatement(SQL.Text, Params);
  if not (poAllowMultiRecordUpdates in Provider.Options) and (RowsAffected > 1) then
  begin
    if Assigned(PS2) then
      PS2.PSEndTransaction(False)
    else
      (Provider.DataSet as IProviderSupport).PSEndTransaction(False);
    Provider.TransactionStarted := False;
    DatabaseError(STooManyRecordsModified);
  end;
  if RowsAffected < 1 then
    DatabaseError(SRecordChanged);
end;

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.
Responder Con Cita
  #6  
Antiguo 12-03-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
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...
Responder Con Cita
  #7  
Antiguo 12-03-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por Bauhaus1975 Ver Mensaje
Por otra parte he visto usando el depurador detenidamente que al ejecutar el siguiente método del provider:
Código Delphi [-]
procedure TSQLResolver.DoExecSQL(SQL: TWideStringList; Params: TParams);
var
  RowsAffected: Integer;
  PS2: IProviderSupport2;
begin
  if Supports(Provider.DataSet, IProviderSupport2, PS2) then
    RowsAffected := PS2.PSExecuteStatement(SQL.Text, Params)
  else
    RowsAffected := (Provider.DataSet as IProviderSupport).PSExecuteStatement(SQL.Text, Params);
  if not (poAllowMultiRecordUpdates in Provider.Options) and (RowsAffected > 1) then
  begin
    if Assigned(PS2) then
      PS2.PSEndTransaction(False)
    else
      (Provider.DataSet as IProviderSupport).PSEndTransaction(False);
    Provider.TransactionStarted := False;
    DatabaseError(STooManyRecordsModified);
  end;
  if RowsAffected < 1 then
    DatabaseError(SRecordChanged);
end;

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).
Eso me temía. Ahora, ¿podrías detener el programa en esa línea que señalas y decirnos qué valor tienen la propiedad SQL.Text y los parámetros de la colección Params (Params.Count, Params [0].Value, Params [1].Value...)?

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.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

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


La franja horaria es GMT +2. Ahora son las 18:16:49.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi