Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   Problemas al cerrar-destruir Tquery, o al hacer segunda consulta (https://www.clubdelphi.com/foros/showthread.php?t=48535)

fonx 27-09-2007 15:01:40

Problemas al cerrar-destruir Tquery, o al hacer segunda consulta
 
Hola, este es mi caso (Delphi5 con access):

Bucle:
Selecciono datos
Proceso datos
Fin Bucle

La primera vez lo hace bien:

Código:

query.active:=false;
 query.SQL.text:=('SELECT * FROM Datos WHERE Historico=No');
query.active:=true;
If query.RecordCount>0 then
  Procesar Datos

Pero las sucesivas no funciona porque no puedo hacer query.active:= false, me casca ahi. Me dice que se ha llegado a la marca de EOF y que para hacer esa operación necesita al menos un registro. Si la primera consulta no devuelve datos entonces el query esta obligatoriamente en EOF.

La solución temporal que he adoptado es que el query sea una variable local a la función de modo que cuando se llega al final de la funcion destruyo el query
Código:

query.Destroy;
pero me casca en el destroy porque me dice que "cannot perform this operation on an open dataset", y como no puedo cerrarlo pues no se si se destruye. Al entrar de nuevo en la funcion la variable query es otra nueva, pero las reservas de memoria anteriores en otras pasadas por esta funcion no se si se liberan o no.

¿Ideas? ¿Soluciones?

maeyanes 27-09-2007 15:46:10

Hola...

Puedes intentar con este código:

Código Delphi [-]
var
  AQuery: TQuery;

begin
  with TQuery.Create(nil) do
    try
      // Asignas valores a propiedades como Database, etc...
      SQL.Text := 'select * from Datos where Historico = No';
      Open;
      If not IsEmpty then
        // Procesar datos
      Close
    finally
      Free
    end
end;

De esta forma dentro de la función creas, usas y destruyes el objeto...

Ahora, si te fijas, usé el método Free para destruir el objeto, no Destroy...



Saludos...

fonx 27-09-2007 16:28:31

No funciona, casca al hacer el close y no libera memoria. Este es el mensaje:

Project xxx.exe raised exception class EOleException with message 'El valor de BOF o EOF es True, o el actual registro se eliminó: la operación solicitada requiere un registro actual'


Código:

while true do
  begin
    Prueba();
  end;

Código:

Procedure Prueba();
Var
  difAnt:real;
  i:integer;
  error:boolean;
  query:TADOQuery;
begin
  Try
  query :=TADOQuery.create(nil);
  query.Connection:=AC1;
  query.SQL.text:=('SELECT * FROM Datos WHERE Historico=No');
  query.Open();
  For i:=1 to query.recordcount do
  begin
      query.next;
  end;
  query.close;
  query.Free;
  Except
      error:=true;
  end;

end;

También probé esta forma:
Código:

Procedure Prueba2();
Var
  difAnt:real;
  i:integer;
  error:boolean;
  query:TADOQuery;
begin
  Try
  query :=TADOQuery.create(nil);
  query.Connection:=AC1;
  query.SQL.text:=('SELECT * FROM Datos WHERE Historico=No');
  query.active:=true;
  For i:=1 to query.recordcount do
  begin
      query.next;
  end;
  query.Destroy;
  Except
      error:=true;
  end;

end;

No libera memoria, ese bucle infinito no para de coger memoria...Casca al hacer el close() o el destroy(). Esto pasa cuando:
  • el query no tiene registros, entonces EOF = true.
  • el query esta posicionado en el ultimo registro, entonces EOF = true.
Si hay registros lo tengo facil porque solo tengo q hacer query.First y ya me lo libera, pero si no hay registros el query no se libera y me queda esa memoria sin liberar...¿Será un bug del Delphi5?

maeyanes 27-09-2007 16:41:38

Hola...

Para que siempre te libere el objeto TADOQuery, usa la construcción try..finally, ya que esta siempre ejecuta la parte del finally haya o no haya excepción...

Y te repito de nuevo, no uses el método Destroy para liberar objetos, ese método es de uso interno de Delphi, usa el método Free...

Sobre tu código de prueba, si haces un while True do, lo único que vas a lograr es un loop infinito, ya que True siempre va a ser True...

Puedes probar lo siguiente:

Código Delphi [-]
if Prueba then
  ShowMessage('Prueba exitosa');


// Código de Prueba
function Prueba: Boolean;
var
   difAnt: Double;
   I: Integer;

begin
  Result := True;
  with TADOQuery.Create(nil) do
    try
      try
        Connection := AC1;
        SQL.Text:= 'SELECT * FROM Datos WHERE Historico=No';
        Open;
        First;
        while not Eof do
          Next;
        Close
      except
        ShowMessage('Ocurrió un error');
        Result := False
      end
    finally
      Free
    end
end;

Sobre TADOQuery, la verdad no sabría decirte si tiene algún tipo de error o limitante en Delphi 5, sería investigar un poco al respecto...



Saludos...

Victor Vega 27-09-2007 16:46:12

Hola...
 
veo q estas usando un bucle...
probaste usar :

Código Delphi [-]
 
if not EOF

fonx 27-09-2007 17:03:11

El while true lo puse yo para que se ejecutara infinitas veces y así ver si no liberaba la memoria, y efectivamente la memoria ocupada crece y crece y crece...

No funciona el close si el query tiene EOF = true, salta una excepcion. Ahora voy a reiniciar el ordenador pq con tanta prueba ya ni funciona...:mad:

Lepe 27-09-2007 21:47:48

Por experiencia, cuando algo no sale, miramos las cosas más absurdas y nos emperramos en que hay un virus en el ordenador que no lo deja funcionar bien.

Ese momento es el idóneo para dejar el puñetero ordenador y hacer otra cosa que no tenga nada que ver con el trabajo ni con ordenador.

El fallo es la propia consulta sql, ya que debe decir: where Historico = 'No' (¿ves las comillas simples? pues faltan en tu sql).

Código Delphi [-]
Procedure Prueba();
Var
   difAnt:real;
   i:integer;
   error:boolean;
begin
  // query es un componente puesto en la ventana
   query.SQL.text:=('SELECT * FROM Datos WHERE Historico=' + QuotedStr(No));
   query.Open();
   while not query1.Eof do
      query.next;

   query.close;
end;

Una observación: Yo he usado QuotedStr que añade comillas simples alrededor de la palabra. Pero no sé lo que espera Access (o ADO), puede que espere comillas dobles... la que está encima del número 2.

Saludos y descansa un poco amigo fonx, te lo mereces.

fonx 27-09-2007 22:21:47

Jajaja, descansar...gracias por el consejo Lepe pero soy programador a tiempo completo, de Delphi en horario laboral y de .Net en mi tiempo libre.

Buen intento pero no. Te explico, la base de datos es access y tiene un tipo de dato que es Si/No. Desde el access lo puedes manejar como un checkbox, para dejarlo en Si o en No, pero accediendo mediante consultas sql lo consultas/manejas dando los valores Si y No, no es una cadena de texto. ¿Me explique?

Gracias por la intencion :), como este programa lo tengo q entregar en un plazo determinado voy a seguir avanzándolo y ya volveré a este error más adelante. No obstante seguid aportando lo que se os pueda ocurrir. Gracias y un saludo

waly2k1 28-09-2007 05:12:48

Probá con...
 
Manejá el campo booleano con 0 o -1, en access -1, SQL Server 1
el campo de tipo bit. Depende si es 0 falso o distinto de 0 (1 o -1) es true
El error que te daba anteriormente se debe a que todas las opciones
de campos/arrays, colecciones, etc. comienzan en 0, a no ser que especifiques lo contrario,
lo cual en VB es posible, pero desconozco si en Delphi está permitido
Además si pones active := false a veces te da problema pq nunca lo abrió, a vos te fallaba directamente la consulta
no te traia nada con la condicion = 'No'

dicho de otra manera:

for i = 0 to query.Recordcount -1

si ponés solo .Recordcount es logico que te de error porque quieres
posicionarte en un registro inexistente ya q al arrancar en 0, pretendes
avanzar uno mas del ultimo y aborta la operacion.

Y no te rindas tan facil, ponele el pecho a las balas!!!

Código:

procedure prueba();
Var
  difAnt:real;
  i:integer;
  error:boolean;
begin
  query.SQL.Clear;
  query.SQL.text := 'SELECT * FROM Datos WHERE Historico=-1';
  query.Open();
  while not query.Eof do
  begin
      MessageBox( Handle, PChar( 'WOW Tengo algo' ), PChar( '¡ A T E N C I O N !' ), MB_ICONWARNING + MB_OK + MB_APPLMODAL);

      query.next;
  end;
  query.close;
end;

Salu2

fonx 28-09-2007 09:03:55

Tampoco waly2k1. Por un lado for i:=1 to query.recordcount es lo mismo que for i:=0 to query.recorcount-1, porque no utilizo el iterador i como índice de acceso a nada sino como contador de iteraciones, y en los dos casos es el mismo número de iteraciones.

El while not query.eof tampoco soluciona nada porque el caso de fallo es el siquiente, centraos en el caso de fallo:

CASO DE FALLO
Cuando quiero cerrar o liberar un query y tiene la propiedad EOF = true no puedo, me da el mensaje:

Project xxx.exe raised exception class EOleException with message 'El valor de BOF o EOF es True, o el actual registro se eliminó: la operación solicitada requiere un registro actual'

Si hago una consulta que no devuelve registros entonces query.EOF es true siempre, siempre, siempre, y entonces no puedo cerrar o liberar ese query. Si la consulta devuelve datos entonces estoy obligado a hacer un query.first o mover el registro actual del query para que query.EOF sea false. ¿Entendeis el fallo?

fonx 28-09-2007 10:55:53

Parece ser que puede q esté en lo cierto y es un bug del motor ADO del Delphi 5, y probablemente se solucionase con las actualizaciones disponibles en la web:

http://info.borland.com/devsupport/delphi/downloads/

Pero no puedo saberlo porque los vínculos a los archivos de actualización que hay en esa página están rotos :mad::mad::mad::mad:...El Delphi Enterprise Update Pack lo pude conseguir aquí en la oficina, pero el Update Pack 2, que es el que actualiza el motor ADO, pues no se de donde lo puedo sacar. ¿Alquien me lo puede facilitar? Solo son 1,7Mb que en un email se pueden enviar sin problema...les mandé un mail a Borland España a ver si ellos pueden conseguirmelo.

El Update Pack 2 es el archivo d5adoupdate2.exe, por si a alguien le suena en su disco duro.

waly2k1 28-09-2007 17:08:08

Reinstala ADO
 
lo que podes hacer es reinstalar ADO, mediante los MDAC q los bajas de la pagina de Microsoft, en caso de que estes seguro de tu problema.

Me hace ruido que el error de cierre es porque nunca lo abrio ya que no podes preguntar por ='No' ya que es un formato de 'muestra', internamente almacena un Nro en el campo booleano.

Te da .eof si no trajo registros, pero si la consulta falló no te da nada y no podés hacer referencia al query como intentas hacerlo.

Al .recordcount no lo podés hacer ya que este te da un nro. por ej 5 cuando tenes 5 registros, pero si comienza en 0 va el for de 0 a 4 (.recordcount-1) y en total si son 5. y no de 1 a 5, ya que la posicion 5 No Existe.

Saludos y espero despejar un poco tus dudas

maeyanes 28-09-2007 17:33:14

Hola...

Cita:

Empezado por waly2k1 (Mensaje 234756)
Te da .eof si no trajo registros, pero si la consulta falló no te da nada y no podés hacer referencia al query como intentas hacerlo.

El query como objeto existe, aun si no devuelve ningún resultado la consulta...

Cita:

Al .recordcount no lo podés hacer ya que este te da un nro. por ej 5 cuando tenes 5 registros, pero si comienza en 0 va el for de 0 a 4 (.recordcount-1) y en total si son 5. y no de 1 a 5, ya que la posicion 5 No Existe.
Aquí creo que andas algo confundido... Un TDataSet no lo puedes recorrer mediante algo como Record[Index], este se recorre mediante los métodos First, Next, Prior y Last...

Así que el loop de fonx: for I := 1 to RecordCount do es correcto, ya que es un equivalente a while not Eof do...


Saludos...

fonx 02-10-2007 09:19:15

Efectivamente mis sospechas eran correctas. Es un fallo del motor ADO, se soluciona con el d5adoupdate2.exe, que es el Update Pack 2. Gracias a todos por la colaboración. El delphi 5 está un poco anticuado pero si alguien pasa por este fallo espero q le sirva este hilo :)


La franja horaria es GMT +2. Ahora son las 07:20:42.

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