Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Error con DBEXPRESS en relacion maestro-detalle (https://www.clubdelphi.com/foros/showthread.php?t=82029)

QuarkBcn 17-01-2013 15:00:49

Error con DBEXPRESS en relacion maestro-detalle
 
Hola a todos ... tengo un problema y no doy con la solución. Estoy trabajando en D2006, DBEXPRESS y necesito solventar lo siguiente

Tenemos una relación maestro detalle, si lo realizo con el BDE, funciona perfecto pero con DBEXPRESS no hay manera.

Como os decía, en una relación maestro - detalle tenemos en el maestro 3 campos clave, y en el detalle tengo los tres campos clave,
si enlazo ambos Querys a través del Datasource del detalle con el Datasource que apunta al maestro, tanto en BDE como DBEXPRESS funciona,
pero el problema viene cuando el detalle necesita filtrar resultados por un cuarto campo que no tiene el maestro. Este cuarto campo,
lo añado como parámetro en la consulta, y a través de código le asigno el valor correcto al parámetro. Pero al abrir el Query da error en DBEXPRESS
Y funciona correctamente, lo mismo, pero con el BDE.

Alguien tiene idea de que falla.

Gracias anticipadas.

Al González 17-01-2013 15:34:44

Cita:

Empezado por QuarkBcn (Mensaje 453567)
Alguien tiene idea de que falla.

Supongo que es pregunta. :)

Sí, creo saber lo que ocurre. Pero antes un par de preguntas:

1. ¿cuál es el mensaje de error exacto?
2. Además de dbExpress, ¿estás utilizando ClientDataSets?

QuarkBcn 17-01-2013 22:44:25

Gracias Al, espero tu respuesta :-)

Ahora no tengo el sistema en marcha para poder indicarte el error, mañana lo adjunto, y si a la segunda pregunta, estaba trabajando con ClientdateSet, pero he probado (en la desesperación :-) ) ... solo con SQLQuery y también falla.

Cita:

Empezado por Al González (Mensaje 453568)
Supongo que es pregunta. :)

Sí, creo saber lo que ocurre. Pero antes un par de preguntas:

1. ¿cuál es el mensaje de error exacto?
2. Además de dbExpress, ¿estás utilizando ClientDataSets?


QuarkBcn 18-01-2013 10:46:08

Buenos días Al, ahí va el mensaje de error.

"Exception class EDatabaseError with message 'Database Server Error: No se han especificado valores para algunos de los parámetros requeridos.' "


Cita:

Empezado por Al González (Mensaje 453568)
Supongo que es pregunta. :)

Sí, creo saber lo que ocurre. Pero antes un par de preguntas:

1. ¿cuál es el mensaje de error exacto?
2. Además de dbExpress, ¿estás utilizando ClientDataSets?


Al González 18-01-2013 19:14:09

Bueno, trataré de explicar lo que sé al respecto.

La clase TClientDataSet no permite que, usando un conjunto de datos detalle, convivan en la misma consulta los parámetros que hacen el filtro de la llave maestra (correspondientes a los campos de IndexFieldNames / IndexName) con parámetros adicionales de la propiedad Params. De ahí lo que comentabas:
Cita:

Empezado por QuarkBcn (Mensaje 453567)
[...] el problema viene cuando el detalle necesita filtrar resultados por un cuarto campo que no tiene el maestro [...]

Cuando un TClientDataSet es detalle de otro conjunto de datos cualquiera, al hacer la llamada a su proveedor (TDataSetProvider) para lanzar la consulta sobre la base de datos, empaca en forma de parámetros los valores que hacen el filtro maestro-detalle y le da ese grupo de parámetros al proveedor. Pero alegremente se olvida de cualquier valor que haya en los objetos de la propiedad Params. En mi opinión se trata de una falla de diseño, y esto me condujo a agregarle una propiedad Boolean de nombre AllParamsWhenDetail (todos los parámetros cuando sea detalle) a un componente que derivé hace tiempo.

Para colmo la clase TSQLQuery y sus similares tienen, también por diseño, la no muy deseable costumbre de reemplazar toda su propiedad Params por aquellos parámetros que le llegan del proveedor. De tal manera que si tu SQLQuery tenía definido cuatro parámetros (tres de relación maestro-detalle y uno extra), al llegarle los tres parámetros del proveedor (porque el TClientDataSet sólo le dio a éste los tres de relación maestro-detalle), el SQLQuery terminará eliminando el cuarto objeto de su propiedad Params e intentará abrir la consulta con sólo tres parámetros. Esto me orilló a crear una clase derivada que conservase en el SQLQuery los parámetros que el proveedor no proporcionara, en lugar de eliminarlos.

Me gustaría ver con detalle lo que estás haciendo para decirte qué te conviene hacer. Soluciones hay varias y algunas depende de la versión de Delphi que estés utilizando. Sería bueno ver esas consultas (tablas, campos, propósito), qué motor de base de datos utilizas, a qué componente y en qué línea de código asignas el valor al cuarto parámetro...En general, algo más de contexto, si fuera posible. :)

Saludos.

QuarkBcn 21-01-2013 13:48:15

Antes que nada darte las gracias por tu detallada explicación. Me temía que fuera un error de diseño del DBEXPRESS, como así ha sido. Es curioso, que el BDE, tenga esto resuelto desde siempre, y que DBEXPRESS no lo tenga solventado. No lo he probado con DBX4. De momento voy a solventar esto desde el BDE, pero más tarde o más temprano voy a tener que ver como lo resuelvo desde DBX.

El código SQL que me comentas, es algo parecido a esto

Maestro:

Código SQL [-]
SELECT * FROM TABLA1

Detalle:

Código SQL [-]
SELECT * FROM TABLA2
WHERE ID1 := ID1 (Se corresponde con el ID1 de TABLA1)
AND ID2 = :ID2 (idem parámetro anterior)
AND ID3 = :ID3 (siendo este el nuevo parámetro para la tabla detalle, el cual se le asigna desde código)
Espero haberte aclarado algo. Si se te ocurre alguna solución, estaré encantado de estudiar lo que me comentes.

Antes de despedirme, quería comentarte, que me ha gustado mucho tú blog "Rescatando Delphi"

Saludos !!!







Cita:

Empezado por Al González (Mensaje 453667)
Bueno, trataré de explicar lo que sé al respecto.

La clase TClientDataSet no permite que, usando un conjunto de datos detalle, convivan en la misma consulta los parámetros que hacen el filtro de la llave maestra (correspondientes a los campos de IndexFieldNames / IndexName) con parámetros adicionales de la propiedad Params. De ahí lo que comentabas:

Cuando un TClientDataSet es detalle de otro conjunto de datos cualquiera, al hacer la llamada a su proveedor (TDataSetProvider) para lanzar la consulta sobre la base de datos, empaca en forma de parámetros los valores que hacen el filtro maestro-detalle y le da ese grupo de parámetros al proveedor. Pero alegremente se olvida de cualquier valor que haya en los objetos de la propiedad Params. En mi opinión se trata de una falla de diseño, y esto me condujo a agregarle una propiedad Boolean de nombre AllParamsWhenDetail (todos los parámetros cuando sea detalle) a un componente que derivé hace tiempo.

Para colmo la clase TSQLQuery y sus similares tienen, también por diseño, la no muy deseable costumbre de reemplazar toda su propiedad Params por aquellos parámetros que le llegan del proveedor. De tal manera que si tu SQLQuery tenía definido cuatro parámetros (tres de relación maestro-detalle y uno extra), al llegarle los tres parámetros del proveedor (porque el TClientDataSet sólo le dio a éste los tres de relación maestro-detalle), el SQLQuery terminará eliminando el cuarto objeto de su propiedad Params e intentará abrir la consulta con sólo tres parámetros. Esto me orilló a crear una clase derivada que conservase en el SQLQuery los parámetros que el proveedor no proporcionara, en lugar de eliminarlos.

Me gustaría ver con detalle lo que estás haciendo para decirte qué te conviene hacer. Soluciones hay varias y algunas depende de la versión de Delphi que estés utilizando. Sería bueno ver esas consultas (tablas, campos, propósito), qué motor de base de datos utilizas, a qué componente y en qué línea de código asignas el valor al cuarto parámetro...En general, algo más de contexto, si fuera posible. :)

Saludos.


QuarkBcn 21-01-2013 13:51:21

En el mensaje anterior se me olvidó comentarte que el problema lo tengo con DELPHI 2006 y una BD MS SQL SERVER 2008 R2.

De todas formas estoy pendiente de empezar a usar DELPHI XE3, el cual solo he tenido tiempo de instalar, pero no de recompilar todos los componentes propios y las aplicaciones.

Saludos !!!



Cita:

Empezado por Al González (Mensaje 453667)
Bueno, trataré de explicar lo que sé al respecto.

La clase TClientDataSet no permite que, usando un conjunto de datos detalle, convivan en la misma consulta los parámetros que hacen el filtro de la llave maestra (correspondientes a los campos de IndexFieldNames / IndexName) con parámetros adicionales de la propiedad Params. De ahí lo que comentabas:

Cuando un TClientDataSet es detalle de otro conjunto de datos cualquiera, al hacer la llamada a su proveedor (TDataSetProvider) para lanzar la consulta sobre la base de datos, empaca en forma de parámetros los valores que hacen el filtro maestro-detalle y le da ese grupo de parámetros al proveedor. Pero alegremente se olvida de cualquier valor que haya en los objetos de la propiedad Params. En mi opinión se trata de una falla de diseño, y esto me condujo a agregarle una propiedad Boolean de nombre AllParamsWhenDetail (todos los parámetros cuando sea detalle) a un componente que derivé hace tiempo.

Para colmo la clase TSQLQuery y sus similares tienen, también por diseño, la no muy deseable costumbre de reemplazar toda su propiedad Params por aquellos parámetros que le llegan del proveedor. De tal manera que si tu SQLQuery tenía definido cuatro parámetros (tres de relación maestro-detalle y uno extra), al llegarle los tres parámetros del proveedor (porque el TClientDataSet sólo le dio a éste los tres de relación maestro-detalle), el SQLQuery terminará eliminando el cuarto objeto de su propiedad Params e intentará abrir la consulta con sólo tres parámetros. Esto me orilló a crear una clase derivada que conservase en el SQLQuery los parámetros que el proveedor no proporcionara, en lugar de eliminarlos.

Me gustaría ver con detalle lo que estás haciendo para decirte qué te conviene hacer. Soluciones hay varias y algunas depende de la versión de Delphi que estés utilizando. Sería bueno ver esas consultas (tablas, campos, propósito), qué motor de base de datos utilizas, a qué componente y en qué línea de código asignas el valor al cuarto parámetro...En general, algo más de contexto, si fuera posible. :)

Saludos.


Al González 21-01-2013 16:54:36

Gracias por la retroalimentación, QuarkBcn. :)

Cita:

Empezado por Al González (Mensaje 453667)
[...] a qué componente y en qué línea de código asignas el valor al cuarto parámetro...

Supongo que lo anterior lo haces más o menos así:
Código Delphi [-]
CDS.Params.ParamValues ['Parametro4'] := Valor;
o bien:
Código Delphi [-]
CDS.Params.ParamByName ('Parametro4').AsXXX := ValorDeTipoXXX;
Seguramente antes de hacer el Open de ese ClientDataSet.

No me agrada la idea de que te sientas orillado a regresar a BDE. Dadas las circunstancias, me parece que una solución sería que declares una clase interpuesta en el código de tu módulo de datos (el que contiene los CDSs), la cual redefina el método virtual DoGetRecords para forzar dentro de él a que la llamada al servidor lleve todos y cada uno de los parámetros. Esto te va a servir desde Delphi 7 hasta versiones más recientes, dado que esas clases han cambiado muy poco desde entonces.

Sólo para confirmar, supongo que antes de abrir el ClientDataSet, éste y el respectivo SQLQuery tienen en su propiedad Params cuatro parámetros que se corresponden. ¿Cierto?

Sin embargo, te aconsejo que antes de ello consideres el uso de conjuntos de datos anidados (nested data sets). En la Web vas a encontrar muchos ejemplos y explicaciones de cómo funcionan. Es algo que no existe en BDE, pero que sí puedes emplear mediante TDataSetProvider y TClientDataSet. Además, este mecanismo va más acorde con un buen manejo de transacciones, ya que registros maestros y detalles se envían todos juntos en el mismo "paquete" a la hora de guardar.

Si ves que por ese camino le puedes dar la vuelta al problema, estupendo (el tratamiento de los parámetros es distinto). De lo contrario podríamos intentar con la primera opción.

Cita:

Empezado por QuarkBcn (Mensaje 453770)
[...] quería comentarte, que me ha gustado mucho tú blog "Rescatando Delphi"

Muchas gracias. No publico muy seguido, pero afortunadamente hay tela de dónde cortar en el tintero. :)

Saludos.

Al.

QuarkBcn 22-01-2013 10:30:14

Muchas gracias por todo Al.

Probaré primero investigando sobre los conjuntos de datos anidados (nested data sets), y veremos que tal funciona el tema.

Te agradezco de nuevo tu colaboración

Saludos !!!


La franja horaria es GMT +2. Ahora son las 07:06:23.

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