PDA

Ver la Versión Completa : Copia de Parameters en ADOQuery


hades2600
21-11-2007, 15:59:46
Buenas a todos.

Tengo un problemilla con Delphi 2007 para Win32 con ADO.

Me explico: estoy intentando crear un componente derivado de TADOQuery, que haga copia de todos los parámetros antes de asignar los nuevos parámetros. Esto parece relativamente simple:



TNewADOQuery = class(TADOQuery)
FcpyParams: TParameters;
public
constructor Create(aOwner: TComponent); override;
procedure SaveParams;
end;

constructor TNewADOQuery.Create(aOwner: TComponent); override;
begin
inherited Create(aOwner);
FcpyParams := TParameters.Create(Self, TParameter);
end;

procedure TNewADOQuery.SaveParams;
begin
FcpyParams.Clear;
FcpyParams.Assign(Parameters); // <- Excepcion
FcpyParams.AssignValues(Parameters);
end;





Pues bien, la instrucción marcada me da una excepción de
"Invalid class typecast" y el problema es que no encuentro una solucion ni veo a qué se puede deber la excepción por ninguna parte.

¿Alguien me puede ayudar?

Lepe
21-11-2007, 17:00:54
No entiendo por qué quieres hacer eso.

Los parámetros se crean después de modificar el SQL de una query. Es más se destruyen los parámetros existentes y solo se crean aquellos que se hace referencia en el SQL.

Quizás si nos explicas por qué quieres hacer eso, te demos una solución más simple.

Saludos

Al González
21-11-2007, 17:30:55
¡Muy buen día a todos!

Hola Hades2600. De antemano te recomiendo que cuando aparezca una excepción en pantalla presiones Ctrl+C para copiar el mensaje al portapapeles y así poder mostrarlo completo.


…raised exception class EInvalidCast with message 'Invalid class typecast'…


La excepción EInvalidCast corresponde a un molde de tipo inválido hecho con el operador As. Hice una prueba similar que me dio el mismo error, pero a simple vista no encontré nada en el código fuente, así que marqué la opción Project-Options-Compiler-Use Debug DCUs para que el depurador se metiera hasta la cocina.

De esta forma encontré que la excepción se origina en el método TParameters.GetCommand.


function TParameters.GetCommand: TADOCommand;
begin
Result := GetOwner as TADOCommand;
end;


GetOwner es un método de toda colección que devuelve el dueño de la misma, es decir, el primer parámetro que es dado cuando se instancia una colección. Como se ve en el código, se asume que el dueño de la colección es un objeto TADOCommand, pero en tu componente usas el propio componente consulta como dueño:


constructor TNewADOQuery.Create(aOwner: TComponent); override;
begin
inherited Create(aOwner);
FcpyParams := TParameters.Create(Self, TParameter); { <-- Self es la instancia TNewADOQuery }
end;


He ahí la causa de la excepción: TParameters.GetCommand trata de moldear un TNewADOQuery como si fuese un TADOCommand. Cabe mencionar que este uso del operador As es necesario porque el método GetOwner está ascendentemente declarado como una función que devuelve un TPersistent. No obstante se espera que el dueño de la colección sea un TADOCommand.

Revisando un poco más el código fuente de ADODB.pas, encontré que el dueño de la propiedad Parameters de un TADOQuery no es el propio componente consulta, sino un subcomponente (componente interno) que la clase declara como propiedad protegida "Command".

Así pues, la solución a tu caso es que uses tal objeto como primer parámetro en la instanciación del objeto TParameters:


FcpyParams := TParameters.Create(Command, TParameter);


No olvides redefinir el destructor Destroy para liberar el objeto FcpyParams, y no dejes de contarnos sobre tus avances.

Al González. :)

P.D. Concuerdo con Lepe en que deberías plantearnos el propósito de todo esto.

hades2600
21-11-2007, 17:40:31
Muchas gracias, Al Gonzalez.

He probado la solución que me has dado y, efectivamente ese era el problema. Llevaba tres días dándole vueltas al código y no encontraba por qué me daba esta excepción.

Lo que estoy haciendo es un componente ADOQuery que se va a utilizar para calcular informes, y que, aunque en el SQL original se hayan obtenido por ejemplo, 200 campos, recalcula el SQL para obtener solo los campos necesarios para calcular el informe.

Lepe
22-11-2007, 00:24:07
- En lugar de crear un descendiente, yo guardaba los campos que necesita cada quickreport (por ejemplo en una tabla para tal fin), y así me olvidaba del asunto.

- Si el caso es más complejo, en caso de quickReports puedes tirar de QrCreateList

Además no entiendo el por qué recrear el sql, si el usuario selecciona un campo, es que quiere verlo en el informe:confused:.

De todas formas veo que el asunto puede ser muy complejo y que, en última instancia, y tras explicar concienzudamente tu problema, al final acabe dándote la razón de recrear el SQL. Por ello, (y por la perfecta explicación de Al González), doy el tema por zanjado :).

Saludos