Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 09-02-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Angry Problemas copiando TIBQuery a TClientDataSet

Hola de nuevo,

Estoy tratando de crear una función para copiar el contenido de un TIBQuery a un TClientDataSet, donde tengo unos problemillas:

La primera cuestión es el error que obtengo al tratar de trabajar con el TClientDataSet en tiempo de ejecución. Creo el objeto, pero al tratar de hacer un open para insertar un registro obtengo el error 'Missing data provider or data packet'. Y sabemos que trabajando en diseño no hay problemas, además lo he podido comprobar -con este ejemplo aquí publicado-

La segunda cuestión, es que funcione la función que adjunto, pues me he basado en una que rodaba por el foro, pero usando TDataSet, el cual que yo sepa no me sirve pues hay que usar una clase hija de TDataSet.

Esta función me es necesaria para tener un paquete de datos disponible tras realizar la query (previamente, y solo una vez) puesto que a veces necesito alimentar varios objetos con el resultado, o tener los datos disponibles sin molestar a la BBDD una y otra vez. Seguramente ya os habréis encontrado alguno con este tema antes.

Aquí va la función que estoy tratando de hacer:

Código Delphi [-]
function cloneQuery(ibQuery:TIBQuery):TClientDataSet;
var
    Campo :string;
    i :integer;
    tabla : TClientDataSet;
begin
    tabla:= TClientDataSet.Create(nil); // Creamos clientdataset y definimos propiedades
    tabla.ProviderName := '';
    tabla.PacketRecords := -1;
    tabla.StoreDefs := true;
    tabla.Open; // Aquí obtenemos el error: "Missing data set provider..."
    // En esta sentencia se ejecuta la query que traerá los datos
    with ibQuery do
        begin
        Open;
        while not EOF do // Iteramos para ir insertando cada registro
          begin
          tabla.Append;
          for i := 0 to FieldCount-1 do
            begin
            Campo := Fields[i].FieldName;
            tabla[Campo] := ibQuery[Campo];
          end;
          tabla.Post;
          Next;
        end;
        Close;
    end;
    tabla.Close;
    result := tabla;
end;

Muchas gracias y un saludo.
Responder Con Cita
  #2  
Antiguo 09-02-2009
Avatar de defcon1_es
defcon1_es defcon1_es is offline
Miembro
 
Registrado: mar 2004
Ubicación: Cuenca - España
Posts: 533
Poder: 21
defcon1_es Va por buen camino
Hola.
Prueba esto:
Código Delphi [-]
function cloneQuery(ibQuery:TIBQuery):TClientDataSet;
var
    Campo :string;
    i :integer;
    tabla : TClientDataSet;
begin
    tabla:= TClientDataSet.Create(nil); // Creamos clientdataset y definimos propiedades
    tabla.ProviderName := '';
    tabla.PacketRecords := -1;
    tabla.StoreDefs := true;
    tabla.Options := tabla.Options + [poAllowCommandText];
    tabla.CommandText := ibQuery.SQL.Text;
    tabla.Open; // Aquí obtenemos el error: "Missing data set provider..."
    // En esta sentencia se ejecuta la query que traerá los datos
    with ibQuery do
        begin
        Open;
        while not EOF do // Iteramos para ir insertando cada registro
          begin
          tabla.Append;
          for i := 0 to FieldCount-1 do
            begin
            Campo := Fields[i].FieldName;
            tabla[Campo] := ibQuery[Campo];
          end;
          tabla.Post;
          Next;
        end;
        Close;
    end;
    tabla.Close;
    result := tabla;
end;
__________________
Progress Openedge
https://abevoelker.com/progress_open...dered_harmful/


Delphi forever...
Responder Con Cita
  #3  
Antiguo 09-02-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
¡Hola!

Lo que buscas es perfectamente viable pasando la información del Query al TClientDataSet de la forma habitual: usando un TDataSetProvider.

Pero si aún lo quieres hacer con la función que has puesto, sólo tendrías que cambiar la instrucción Open por CreateDataSet.

Pruébalo y nos dices cómo te funciona.

Una cosa más: no hagas el Close al conjunto de datos cliente, porque eso causará que se pierda todo su contenido.

Saludos.

Al González.
Responder Con Cita
  #4  
Antiguo 09-02-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Muchas gracias por vuestro tiempo y ayuda.
He probado vuestros consejos y voy con las respuestas:

Cita:
Empezado por defcon1_es Ver Mensaje
tabla.Options := tabla.Options + [poAllowCommandText];
tabla.CommandText := ibQuery.SQL.Text;
Parece que no funciona. Además parece que el TClientDataSet no tiene la propiedad 'options'.

Cita:
Empezado por Al González Ver Mensaje
¡Hola!
Pero si aún lo quieres hacer con la función que has puesto, sólo tendrías que cambiar la instrucción Open por CreateDataSet.
Sí, prefiero hacerlo con la función puesto que creo que es más 'portable' a mis casos... He probado cambiar Open por CreateDataSet como dices, pero ahora el error (casi me lo esperaba) es: 'No fields defined'.
¿Tengo que definir los campos previamente, con fielddefs?
¿Hay alguna forma de hacerlo automaticamente, es decir que lo coja del resultado de la query?

Otra cosa que me ronda la cabeza es lo que comentas de no poder cerrar ¿Te refieres al clientdataset?... puf, entonces la funcionalidad queda bastante reducida, ¿no?
A ver qué aconsejais... esto está apunto de salir, y esta función es de esas a usar en todo proyecto...

Un saludo.
Responder Con Cita
  #5  
Antiguo 10-02-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
prefiero hacerlo con la función puesto que creo que es más 'portable' a mis casos... He probado cambiar Open por CreateDataSet como dices, pero ahora el error (casi me lo esperaba) es: 'No fields defined'.
¿Tengo que definir los campos previamente, con fielddefs?
Ah, claro, el conjunto de datos cliente (TClientDataSet) debe tener ya los campos que usará (lista de objetos TField en la propiedad Fields) o al menos sus definiciones (propiedad FieldDefs). Olvidé ese pequeño detalle.

Cita:
Empezado por ayuda de Delphi
If the FieldDefs property contains values, these values are used to create field definitions. Otherwise the Fields property is used. One or both of these properties must contain values in order to create a dataset. If neither property is set, CreateDataSet raises an exception.

Cita:
Empezado por Bauhaus1975 Ver Mensaje
¿Hay alguna forma de hacerlo automaticamente, es decir que lo coja del resultado de la query?
Desafortunadamente no existe una solución nativa que te copie (clone) los objetos campos de un conjunto de datos en otro. Es medianamente laborioso implementarla con un ciclo For que recorra la propiedad Fields del conjunto de datos origen (el TIBQuery, en este caso) y por cada campo cree una instancia de la misma clase en el conjunto de datos destino (el nuevo TClientDataSet), además de asignar las propiedades de cada campo copiado (al menos las esenciales como FieldName, Size, etc. y otras que requieras como DisplayFormat, Currency, etc.).

Si estás usando Delphi 7 o 2007 y no tienes inconveniente en emplear una de mis funciones, en GH Freebrary encontrarás un procedimiento llamado ghCopyFields que realiza esa tarea de "reproducción de campos". Tu función quedaría más o menos así (eliminé las sentencias innecesarias):

Código Delphi [-]
Uses
  GHFData;
...
function cloneQuery(ibQuery:TIBQuery):TClientDataSet;
var
    Campo :string;
    i :integer;
    tabla : TClientDataSet;
begin
    tabla:= TClientDataSet.Create(nil); // Creamos clientdataset y definimos propiedades
    ghCopyFields (ibQuery, tabla);  // Le creamos los mismos campos que a ibQuery
    tabla.CreateDataSet;  // Abrimos el conjunto de datos vacío

    // En esta sentencia se ejecuta la query que traerá los datos
    with ibQuery do
        begin
        Open;
        while not EOF do // Iteramos para ir insertando cada registro
          begin
          tabla.Append;
          for i := 0 to FieldCount-1 do
            begin
            Campo := Fields[i].FieldName;
            tabla[Campo] := ibQuery[Campo];
          end;
          tabla.Post;
          Next;
        end;
        Close;
    end;

    { Este es el "Close" que sugiero quitar.  Si acabas de crear y rellenar
      el clon, cerrarlo antes de usarlo no tiene sentido.  Ciérralo
      después, fuera de esta función, cuando ya no vayas a usarlo . }
//    tabla.Close;

    result := tabla;
end;


Cita:
Empezado por Bauhaus1975 Ver Mensaje
Otra cosa que me ronda la cabeza es lo que comentas de no poder cerrar ¿Te refieres al clientdataset?... puf, entonces la funcionalidad queda bastante reducida, ¿no?
Me refiero al Close prematuro que comenté arriba, en la función. Lo normal sería cerrar el nuevo conjunto de datos cuando ya no lo necesites (mejor aún, destruirlo por completo), pero no cuando acabas de crearlo. Lo usual sería algo como esto:
Código Delphi [-]
MiCDS := cloneQuery (QueryX);

Try
  // Uso de MiCDS
Finally
  MiCDS.Free;
End;

Espero te sirva lo escrito y mi código. Coméntanos cómo te resulta.

Un saludo.

Al González.

Última edición por Al González fecha: 10-02-2009 a las 01:21:59.
Responder Con Cita
  #6  
Antiguo 10-02-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Hola y gracias de nuevo Al González por tus 'nutridas' respuestas.
Tendré en cuenta la librería que propones, pero seguí probando con la función y se me ocurrió que si ejecuto la query y luego copio los FieldDefs, mantedría la estructura de campos. Así con este enfoque me ha funcionado perfectamente, sólo había un error: La sentencia tabla.Append tuve que cambiarla por tabla.Insert para que añadiera cada nuevo registro.

En cuanto al cierre del DataSet. Si cierro el data set ¡no se pierden los registros! lo he vuelto a abrir y ahí, estan los puedo recorrer y verificar uno a no. Por tanto esto esto funciona según he probado:

Código Delphi [-]
// Suponemos QueryX como el TIBQuery con el SQL listo para ejecutar
lista:= cloneQuery(QueryX); // Realizamos query y copia del data set según nuestra función.
while not (lista.EOF) do
begin
       showmessage('ID del registro'+lista.FieldByName('ID'));
       lista.Next;
end;
lista.Close;
lista.Open;
lista.First;
while not (lista.EOF) do
begin
        showmessage('ID del registro'+lista.FieldByName('ID'));
        lista.Next;
end;

Y aquí va como ha quedado la ULTIMA versión de la función que hemos estado trabajando:

Código Delphi [-]
function TEquipoCompTemp.cloneQuery(ibQuery:TIBQuery):TClientDataSet;
var
    Campo :string;
    i :integer;
    tabla : TClientDataSet;
begin
    tabla := TClientDataSet.Create(nil);
    tabla.ProviderName := '';
    tabla.PacketRecords := -1;
    tabla.StoreDefs := true;
    // Realizamos la query
    ibQuery.Open();
    // Copiamos estructura de campos
    tabla.FieldDefs := ibQuery.FieldDefs;
    // Abrimos DataSet
    tabla.CreateDataSet;
    with ibQuery do
        begin
        while not EOF do
          begin
          tabla.Insert; // Hemos cambiado Append por Insert
          for i := 0 to FieldCount-1 do
            begin
            Campo := Fields[i].FieldName;
            tabla[Campo] := ibQuery[Campo];
          end;
          tabla.Post;
          Next;
        end;
        Close;
    end;
    result := tabla;
end;

Un saludo.
Responder Con Cita
  #7  
Antiguo 17-02-2009
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: may 2005
Ubicación: Málaga
Posts: 135
Poder: 20
Bauhaus1975 Va por buen camino
Añadir sólo un apunte:

Cita:
Empezado por Bauhaus1975 Ver Mensaje
Así con este enfoque me ha funcionado perfectamente, sólo había un error: La sentencia tabla.Append tuve que cambiarla por tabla.Insert para que añadiera cada nuevo registro.
Esto ha sido un 'cuele' por otras causas. Funciona perfectamente Insert y Append no hagan caso.

Por lo demás la función funciona perfectamente y el dataset puede abrirse y cerrarse que los datos siguen ahí.

Saludos.
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
Problemas copiando y pegando documentos mixtos sue23cr Varios 1 13-07-2007 10:32:21
Problemas al actualizar un TClientDataset y ADO PEDRO_PASAMAR Conexión con bases de datos 1 30-11-2004 10:52:46
Problemas con TClientDataSet dmasson Conexión con bases de datos 5 30-05-2004 21:17:28
Problemas con In en TIBQuery Rabata Conexión con bases de datos 1 15-10-2003 13:56:59
Problemas con In en TIBQuery Rabata SQL 1 15-10-2003 13:56:59


La franja horaria es GMT +2. Ahora son las 13:27:31.


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