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 14-05-2004
Toni Toni is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona - España
Posts: 364
Poder: 21
Toni Va por buen camino
Problema relacion maestro-detalle (Nested Dataset)

Hola,

Ante todo deciros que llevo dias consultando el foro antigüo y el nuevo, y no consigo encontrar un post con la solucion a mi problema concreto. Si que hay muchos post al respecto.

Estoy realizando una relacion de maestro-detalle de 2 querys de lado del servidor. De tal forma que desde el cliente mediante un ClientDataSet recibira las dos querys relacionadas.

En un principio lo unico que no me funciona, es que al abrir el ClienteDataSet desde el cliente, no me muesta los registros del detalle.

Todo esto lo estoy realizando en C++ Builder 5, IB6, IBX 5.04 y Midas, de la siguiente manera:

Tengo definido en un TRemoteDataModule los siguientes componentes:

TBIQuery1 DocCabecera
TBIQuery2 DocDetalle (DataSource = DataSource1)
TIBUpdateSQL1 (asignado a la propieda TIBQuery1->UpdateObject)
TIBUpdateSQL2 (asignado a la propieda TIBQuery2->UpdateObject)
TDataSource1->DataSet = DocCabecera

Para las querys utilizo el conjunto TIBQuery's + TIBUpdateSQL, para que sean querys modificables.

La relacion maestro-detalle la realizo asignando a la propiedad DataSource del query DocDetalle un TDataSource que apunta a al query DocCabecera.

En las 2 querys tengo creados los campos como persistentes y asignado a true la propiedad ProviderFlags->pfInKey de los campos de la clave primaria.

La query cabecera es del estilo:

select * from "DocCabecera"
where "idEmpresa"=:P_EMPRESA and "idLibro"=:P_LIBRO and "idDocumento"=:P_DOCUMENTO;

La query detalle es del estilo:

select * from "DocDetalle"
where "DocDetalle"."idEmpresa"=:"idEmpresa" and "DocDetalle"."idLibro"=:"idLibro" and "DocDetalle"."idDocumento"=:"idDocumento";

Asigno el query DocCabecera a un DataSetProvider con la propiedad UpdateMode = upWhereKeyOnly.

En la parte cliente tengo un ClienteDataSet1 que apunta al DataSetProvider del query DocCabecera. En este ClientDataSet tengo los campos tambien como persistentes y tengo uno que se llama DocDetalle de tipo DataSet.

Este campo de tipo DataSet lo asigno a otro ClientDataSet2 en tiempo de diseño, en la propiedad DataSetField. Tambien he probado a asignarlo medeante codigo, pero todo sigue igual.

Estos ClientDataSet's los tengo enlazados a unos TDataSource que a su vez estan enlazados a unos grids.

Cuando abro los ClientDataSet's no me sale ningun error, lo unico que no me salen los registros del detalle. Eso si el grid muestra los campos del detalle (en blanco).

En un principio creo que la relacion esta bien hecha, pues he seguido todos los pasos que he leido en todos los post.

Saludos,
__________________
Saludos,

Bitman
Responder Con Cita
  #2  
Antiguo 14-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Hola.

Cita:
Empezado por Toni
Cuando abro los ClientDataSet's no me sale ningun error, lo unico que no me salen los registros del detalle. Eso si el grid muestra los campos del detalle (en blanco).
Supongo que solo haces el Open en el ClientDataset1 (DocCabecera), puesto que el ClientDataset2 ya se abrirá solo.

Solo quería comentar que todo lo que haces es correcto. Parece que tienes los componentes bien enlazados, y debería funcionar. Supongo que habrá un bug en algun lado, pero al no usar C++ Builder no lo puedo probar.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #3  
Antiguo 14-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Por cierto, asegurate de tener el TBIQuery2 (DocDetalle) cerrado. Una vez lo deje abierto, y entonces no me cargaba los detalles.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #4  
Antiguo 14-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Otra cosa (aunque no tiene nada que ver con el problema). Los TIBUpdateSQL no són necesarios, los puedes quitar. Puesto que las modificaciones no las realiza el IBQuery, sino que el Provider envia sentencias SQL (Insert/Update/Delete) directamente a la conexión (el IBDatabase).

Unicamente se usarian los TIBUpdateSQL, si activas a True el Flag ResolveToDataset en las Opciones del Provider.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).

Última edición por guillotmarc fecha: 14-05-2004 a las 21:18:12.
Responder Con Cita
  #5  
Antiguo 14-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Finalmente, otra cosa que no veo muy clara, es el uso de comillas en la definición de parámetros en el Query detalle. ¿ Realmente es necesario ?, nunca he utilizado parámetros con minúsculas, pero no estoy nada seguro que necesiten las comillas.

Por si acaso, prueba también con (solo te va a llevar 2 minutos) :

select * from "DocDetalle"
where "DocDetalle"."idEmpresa"=:idEmpresa and "DocDetalle"."idLibro"=:idLibro and "DocDetalle"."idDocumento"=:idDocumento;

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #6  
Antiguo 17-05-2004
Toni Toni is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona - España
Posts: 364
Poder: 21
Toni Va por buen camino
Hola Guillotmarc,

Gracias por todos tus comentarios, me lei todos tus post al respecto del anterior foro.

En principio tengo la ultima actualizacion de las ibx para C++ Builder 5 (ibx 5.04) que yo conozca.

He intentado aislar el problema creando un proyecto nuevo y haber si conseguia averiguar por donde iva la cosa.

He creado un proyecto nuevo y pruebo de realizar todo este montaje en un unico TDataModule en una aplicación normal (1 capa).

Primero he probado a realizar la relacion maestro-detalle solo con los componentes ibx y unos TDataSource directamente a unos grids y me funciona a la primera.

Una vez funcionando esto añado los componentes DataSetProvider y los dos ClientDataSet configurados tal y como comente en el 1er post, e un principio tampoco me funcionaban, finalmente he tocado tantas cosas que ya me visualiza el maestro y detalle, pero el funcionamiento no es del todo el esperado.

No se el porque todavia pero si intento abrir el ClientDataSet1 (cabecera) me da un error (cannot perform this operation on a closet dataset), lo curioso es que abro el ClientDataSet2 y me abre los 2.

Para que me medio funcionase tuve que poner en los campos persistentes de los clientDataSet el flag pfInWhere a false en todos los campos que no pertenecian a la clave principal, eso al tener puesto en el DataSetProvider la porpiedad UpdateMode a upWhereKeyOnly (es esto normal?)

Otra cosa estraña que me hace es cuando doy de alta un nuevo detalle, si no es el primer detalle de esa cabecera me lo guarda sin problemas, si resulta que es el primer detalle de la cabecera no me lo guarda.

Total que ahora si que salen los detalles pero el comportamiento no es el esperado, voy a probar a eliminar todo el datamodule y a empezar de nuevo porque he tocado ya de todo.

Acabo de probar a utilizar los nombres de parametros sin comillas tal y como me dices y en principio funciona igual.

Muchas gracias de nuevo por el interes,

Saludos,
__________________
Saludos,

Bitman
Responder Con Cita
  #7  
Antiguo 17-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Hola.

Cita:
Empezado por Toni
Una vez funcionando esto añado los componentes DataSetProvider y los dos ClientDataSet
Supongo que solo añades un TDatasetProvider, el que va a usar el ClientDataset de cabecera.

Cita:
Empezado por Toni
No se el porque todavia pero si intento abrir el ClientDataSet1 (cabecera) me da un error (cannot perform this operation on a closet dataset), lo curioso es que abro el ClientDataSet2 y me abre los 2.
Curioso. Parece como si la relación estuviese al revés. Al abrir el ClientDataset de cabecera, debería abrir los dos.
En cambio no debe permitir abrir el ClientDataset de detalles (puesto que va unido al ClientDataset de cabecera), y si no recuerdo mal, el error que debe dar es el que comentas.

Cita:
Empezado por Toni
Para que me medio funcionase tuve que poner en los campos persistentes de los clientDataSet el flag pfInWhere a false en todos los campos que no pertenecian a la clave principal, eso al tener puesto en el DataSetProvider la porpiedad UpdateMode a upWhereKeyOnly (es esto normal?)
En absoluto, una vez configurado el UpdateMode a WhereKeyOnly, el único flag que debería tener en cuenta es el pfInKey. Es como si no se usará el DatasetProvider en el que has configurado el UpdateMode.

Cita:
Empezado por Toni
Otra cosa estraña que me hace es cuando doy de alta un nuevo detalle, si no es el primer detalle de esa cabecera me lo guarda sin problemas, si resulta que NO es el primer detalle de la cabecera no me lo guarda.
Esto tampoco es normal.

Tén en cuenta de que los campos de relación (IdEmpresa, IdLibro, IdDocumento) no los rellena automaticamente el ClientDataset. Por lo que tienes que hacerlo manualmente. Yo utilizo el AfterInsert del ClientDataset de detalles.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #8  
Antiguo 17-05-2004
Delfino Delfino is offline
Miembro
 
Registrado: jul 2003
Ubicación: Madrid
Posts: 974
Poder: 21
Delfino Va por buen camino
Hace tiempo q no uso el ClientDataset pero si no recuerdo mal tiene un metodo llamado FetchDetails, no se si te puede servir, espero q al final solcuiones el problema pq a mi el CDS me ha dado mas q un rompe cabeza aunque al final se soluciona..
Responder Con Cita
  #9  
Antiguo 17-05-2004
Toni Toni is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona - España
Posts: 364
Poder: 21
Toni Va por buen camino
Hola Marc,

Te contesto:

Correcto, solo tengo un DataSetProvider enlazado con el ClientDataSet de cabecera.

También he descubierto porque no me permitía realizar un open en el ClientDataSet1, era por tener la propiedad poFetchDetailsOnDemand a true en el DataSetProvider. En algún sitio vi que decía que se tenia que activar, pero debí entender mal.

Otro detalle también era en el ClientdDataSetDetalles la propiedad PacketRecords tiene que estar a 0 y lo tenia puesto a -1.

Ahora parece que ya funciona correctamente la relacion maestro-detalle, lo unico extraño es que de vez encuando cuando añado un registro en el detalle mediante Append (para que se posicione en la ultima posicion del grid) desaparecen los demas registros del grid, cuando finalizo la entrada del registro vuelven a aparecer. Queda muy feo, no lo hace siempre, y mas bien cuando solo hay 1 registro anterior.

Otra cosa es que a mi automaticamente me rellena los campos relacionados con el maestro (idEmpresa,idLibro,idDocumento). No tengo que hacerlo por codigo como tu me dices.

Ahora mi ultimo problema con la cuestion es el sistema que estoy utilizando para enumerar los documentos, utilizo un trigger en la bbdd. Entonces cuando creo un documento nuevo yo mediante codigo le asigno un numero ficticio de documento (999999) y en el momento de guardarlo la bbdd genera el real.
El problema es que no me guarda el detalle, porque tiene el nº documento (99999) y no me recupera el bbdd.

Utilizo este sistema de enumeracion de documentos porque asi no tengo el problema de tener saltos en la numeracion de los docs.

Alguna idea?

Saludos,
__________________
Saludos,

Bitman
Responder Con Cita
  #10  
Antiguo 17-05-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Hola.

Yo prefiero no utilizar Triggers. Puesto que el clientdataset no se entera del valor asignado al campo, hasta que no haces un refresh y vuelves a cargar los datos.

Por eso, utilizo un procedimiento almacenado, que me devuelve el siguiente nº de documento, y lo asigno desde Delphi. Aunque yo lo calculo y asigno en el momento de crear el registro de cabecera, de forma que lo pueden utilizar los detalles en el momento de crearse en su correspondiente clientdataset.

Pero esta forma tiene el problema que comentas de crear saltos (que normalmente en mis programas no tiene ninguna importancia). Si quieres evitarlo, una forma es esperar a calcular el próximo nº documento, y asignarlo, a justo antes de llamar al ApplyUpdates. Aunque tendrás que hacer posteriormente un recorrido sobre el clientdataset de detalles, para asignarles el nuevo valor a todos los registros.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #11  
Antiguo 19-05-2004
Toni Toni is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona - España
Posts: 364
Poder: 21
Toni Va por buen camino
Hola,

Muchas gracias por la ayuda recibida,

Saludos,
__________________
Saludos,

Bitman
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


La franja horaria es GMT +2. Ahora son las 08:32:08.


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