Ir al contenido


Foto

Desenmarañando el CommandText


  • Por favor identifícate para responder
30 respuestas en este tema

#1 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 08 julio 2009 - 09:13

Amigos quiero plantear con ustedes la siguiente inquietud sobre esta propiedad de los TClientDataSet, dada esta otra . Y tambien por lo que comenta la misma ayuda de Delphi:

CommandText specifies what data the client dataset wants to receive from its (internal or external) provider. It is either
An SQL statement (query) for the database server to execute.

The name of a table or stored procedure.

If the client dataset uses an internal provider, CommandText is required.
If the client dataset uses an external provider component, CommandText represents a replacement for the property that the source dataset uses to identify its data (the SQL of a query, or the name of a table or stored procedure). If the provider's Options property does not include poAllowCommandText (which, by default, it does not), then CommandText has no effect.

When CommandText is a non-empty string, its value is sent to the provider when the client dataset opens or when you call the Execute method. The specified SQL command, table, or stored procedure overrides the current value of the provider's associated dataset.

If the SQL statement takes parameters, be sure that they are in the correct order, as the provider performs parameter binding on CommandText statements by index only.


Entonces, ¿realmente como se ejecuta una sentencia pasada por esta propiedad?, ¿como y cuando se ve afectada?.

Saludos!
  • 0

#2 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 08 julio 2009 - 09:43

¿Bonito titulo no?  :D

Amigos quiero plantear con ustedes la siguiente inquietud sobre esta propiedad de los TClientDataSet, dada esta inquietud https://forums.embar...133900&tstart=0 (No me juzguen, mi ingles no es muy bueno  :p). Y tambien por lo que comenta la misma ayuda de Delphi:


Entonces, ¿realmente como se ejecuta una sentencia pasada por esta propiedad?, ¿como y cuando se ve afectada?.

Saludos!


Resulta que este componente incluye otra propiedad llamada CommandType que permite al controlador interno del ClientDataset saber como ejecutar el commandText. Siendo este una tabla o un Sp o un query.

Esa propiedad define que manejador es el responsable de ejecutar lo contenido en el CommandText. Si revisas el código fuente de la clase lo notarás.


Saludos y espero haya resuelto tu duda.
  • 0

#3 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 08 julio 2009 - 10:09

Resulta que este componente incluye otra propiedad llamada CommandType que permite al controlador interno del ClientDataset saber como ejecutar el commandText. Siendo este una tabla o un Sp o un query.

Esa propiedad define que manejador es el responsable de ejecutar lo contenido en el CommandText. Si revisas el código fuente de la clase lo notarás.


Gracias Edgar, efectivamente tambien encontre información al respecto de lo que comentas, lo que no estoy seguro es si este se pueda "definir a gusto", es decir, si se trata de un SP o de un Query y si existe una diferencia realmente; creo tambien que se define por la manera en que la sentencia es ejecutada, si es por Open o Execute.

Saludos!
  • 0

#4 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 09 julio 2009 - 10:21

Hola,
he seguido con mi investigación y tengo lo siguiente:
Aqui hay una información muy interesante acerca de dbExpress http://conferences.c...p/article/32229 donde podemos denotar lo siguiente:

Connecting to data requires the database to be identified, the data table(s) and columns selected and a request for the defined data. The major difference between dbExpress and the other RAD data connectivity options is dbExpress only supports unidirectional, read-only cursors for data retrieval. This means no data is buffered and some of the features available in the other data connectivity options are not applicable.


En pocas palabras, la "magia" la realiza DataSnap (MIDAS) como se explica aqui:

The DataSetProvider creates datapackets based on the SQL statement defined by the CommandText property and used by the SQLDataSet. The datapackets are cached in memory. When edits are sent back to the database, the DataSetProvider processes datapackets containing just the modified records; it creates the appropriate SQL statements that are sent to the database.


En este sentido, es necesario utilizar el ClientDataset y el DataSetProvider para que dbExpress funcione bi-direcccionalmente.

Entonces, el esqueleto se puede interpretar de la siguiente manera, el ClientDataSet entrega los llamados data-packets o paquetes de datos al DataSetProvider, en este caso (mi inquietud planteada en el enlace de arriba) estamos hablando del valor que es pasado mediante la propiedad CommandText. El DSP llama un procedimiento denominado SetCommandText que recibe el valor antes dado por el CDS, este es antes verificado asi como que su propiedad poAllowCommandText este habilitada, de no ser asi, tenemos el primer error de la base de datos.
Hecho esto es llamada la interface IProviderSupport a la que se es asignado el Dataset, en este caso el TSQLQuery y se llama el procedimiento PSSetCommandText que hace lo siguiente:

The value of the CommandText parameter replaces the dataset’s SQL statement (if it has one), or replaces the name of an underlying database table or stored procedure.

Ejecutandolo con el procedimiento PSExcecute:

The provider component calls PSExecute to implement its Execute method. If the dataset represents a query or stored procedure that does not return a cursor, this method executes the query or stored procedure. If the provider Options includes poAllowCommandText and the dataset supports the PSSetCommandText method, the statement specified by PSSetCommandText may be executed instead.


Por lo que el valor incial de la consulta en el SQLQuery deberí­a ser reemplazada temporalmente por nuestra nueva consulta desde el CommandText.

Ahora bien, si tenemos una relación Maestro-Detalle y en el detalle ejecuto la nueva sentencia, no obtengo respuesta, ¿porque?, pienso tal vez que esta se ejecuta dentro de los valores disponibles en el encabezado, aún así­, si hubiera uno solo obtenemos un error de la base de datos...

Esto seguira, hasta tener respuesta  :D

Saludos!

  • 0

#5 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 09 julio 2009 - 05:11

Continuando...

En pruebas anteriores y con lo que respaldo mi teoria (en el Master-Detail) descubro que si dicha relacion se crea directamente en el TSQLQuery y no el TClientDataSet,

Imagen Enviada

En este esquema se representan de azul los componentes TSQLQuery y el TDataSource en color gris


el CommandText en ambos funciona correctamente y sin ningun inconveniente; el problema en este caso, se trata del mantenimiento de tal relación, ya que debe ser efectuada "a pedal" , por lo que el trabajo se hace más tedioso.

En el esquema actual

Imagen Enviada

Aquí­ el TClientDataSet son los azules y el TDataSource el gris


Es donde se origina esta polémica (bueno más bien mí­a  :p), pero a su vez es la manera más simple y efectiva (con ahorro de código incluido) para realizar actualizaciones y busquedas.

PD: Adjunto tambien un pequeño ejemplo para que se ilustren de la idea, solo descompriman en C.

Saludos!

Archivos adjuntos


  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 09 julio 2009 - 05:30

Hola

Ejecute tu programa despues de configurar una conexión nueva y al presionar el Button2 me muestra este error


---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EDatabaseError with message 'Database Server Error: unassigned code'.
---------------------------
Break  Continue  Help 
---------------------------


Salud OS
  • 0

#7 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 09 julio 2009 - 05:35

Hola

Ejecute tu programa despues de configurar una conexión nueva y al presionar el Button2 me muestra este error



---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EDatabaseError with message 'Database Server Error: unassigned code'.
---------------------------
Break  Continue  Help 
---------------------------


Salud OS


Exacto ego, ese es uno de los errores que quiero descubrir (algunas veces cambian) y el porque no funciona como deberia ser  :D

Saludos!
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 09 julio 2009 - 05:49


Exacto Eliseo, ese es uno de los errores que quiero descubrir (algunas veces cambian) y el porque no funciona como deberia ser  :D

Saludos!


Hola

Hay dos cosas, se recomienda que después de cambiar el CommandText debes de invocar el método ClientDataSet.Execute, y después el ClientDataSet.Open.

La otra es que debemos ver porque si está abierto un ClientDataSet el otro genera el error, hice esto y ya funciona sin errores.



delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   ClientDataSetItem.Close;
  4.   ClientDataSetCliente.Close;
  5.   ClientDataSetCliente.CommandText := 'SELECT * FROM CLIENTE WHERE ID_CLIENTE = ' + Edit1.Text;
  6.   ClientDataSetCliente.Execute;
  7.   ClientDataSetCliente.Open;
  8. end;
  9.  
  10. procedure TForm1.Button2Click(Sender: TObject);
  11. begin
  12.   ClientDataSetCliente.Close;
  13.   ClientDataSetItem.Close;
  14.   ClientDataSetItem.CommandText := 'SELECT * FROM ITEM WHERE ID_CLIENTE = ' + Edit2.Text;
  15.   ClientDataSetItem.Execute;
  16.   ClientDataSetItem.Open;
  17. end;



Habrá que profundizar en el tema.

Salud OS
  • 0

#9 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 10 julio 2009 - 07:25

¿Y el segundo te muestra resultados?

En cuanto al método execute y open, dirí­a que se trata de gustos y necesidades, ya que el execute no retorna datos al ClientDataSet, digamos que se usarí­a para ejecutar un SP. El open realiza ambas, ejecuta y trae los datos a memoria.

Saludos!
  • 0

#10 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 10 julio 2009 - 12:26

¿Y el segundo te muestra resultados?

En cuanto al método execute y open, dirí­a que se trata de gustos y necesidades, ya que el execute no retorna datos al ClientDataSet, digamos que se usarí­a para ejecutar un SP. El open realiza ambas, ejecuta y trae los datos a memoria.

Saludos!


No me muestra datos amigo, solo un registro nulo

Salud OS
  • 0

#11 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 10 julio 2009 - 01:56

No me muestra datos amigo, solo un registro nulo


Parte causante de este hilo amigo  :D
  • 0

#12 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 13 julio 2009 - 09:18

¿Nested DataSet la solución?

http://edn.embarcade...m/article/29825

Saludos!

  • 0

#13 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 13 julio 2009 - 03:26

Hola,
¿alguien ha llegado a trabajar con la manera antes comentada?
  • 0

#14 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 13 julio 2009 - 04:24

Si, y como todo en la vida es muy eficiente para cierto tipo de situaciones y no tanto para otras, si se va a trabajar de esta manera hay que tener especial cuidado con el diseño inicial de la BD, mas que todo en la asignación de  las claves primarias tanto en las tablas maestras como en las de detalles, así­ como en el desarrollo de procedimientos almacenados que luego ayuden a asignar valores a las claves primarias para no sufrir tanto a la hora de la resolución. Es de anotar que en aplicaciones de 3 capas todo el peso de la resolución racae sobre los TDatasetProvider de el servidor, en donde hay que utilizar ciertas técnicas  para tener éxito.

Por ejemplo una clásica relación maestro - detalles de dos tablas una de Facturas y otra de lí­neas de factura; si en un diseño clásico inicial asignas las claves primarias mediante un generador y un trigger, no hay forma alguna de que estos valores vayan al lado cliente en donde la tabla de detalles necesita obligatoriamente el valor de la  clave primaria de la tabla maestra. En este punto es que hay que hacer equilibrio sobre la cuerda floja.

Igual si nesecitas hacer algún desarrollo, no dudes en consultar, que aunque mis conocimientos son escasos y precarios, he podido terminar con éxito varias aplicaciones utilizando la técnica de Datasets anidados.

Saludos
  • 0

#15 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 13 julio 2009 - 04:55

Hola Wilson,
gracias, lo que en realidad me interesa más de esta técnica es ver los pro y los contra, comparado con lo que podrí­a llamarse la técnica tradicional. El fin es determinar si en esta manera es posible ejecutar con éxito el ejemplo que antes dispuse en el hilo, la idea final es determinar como es disparado el CommandText desde el detalle y como se ve afectado su resultado por las relaciones M-D.

Saludos!
  • 0

#16 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 14 julio 2009 - 07:25

El fin es determinar si en esta manera es posible ejecutar con éxito el ejemplo que antes dispuse en el hilo.


Definitivamente no es posible de ninguna de las dos formas, cuando se hace de la manera tradicional que tu dices el proveedor ignora el ComandText y lo que hace es crear al vuelo una consulta basada en la setencia SQL del query de detalles  pasando como parámetro el valor actual del campo responsable de la relación de la tabla maestra; cuando se hace con datasets anidados es obligatorio que el nombre del parámetro del query de detalles sea igual al nombre del campo responsable de la relación, cuando de este modo intentas pasar otro CommandText al ClientDataset de detalles simplemente no opera porque con esta técnica el ClientDataset de detalles no tiene asignado un proveedor o un archivo a quien remitirle la sentencia.

Ahí­ te devuelvo tu ejemplo modificado para trabajar con Datasets anidados, podrás notar los siguientes cambios:

Eliminación del proveedor de detalles.

Cambio del nombre del parámetro en el query de detalles.

Adición de un DataSource para anidar los querys.

Creación de campos persistentes, notese el nombre del último campo en el ClientDataset maestro que corresponde al nombre completo del query de detalles.

Suspensión de las propiedades  MasterSource, MasterFields, IndexFieldName y ProviderName del ClientDatset de detalles.

Adición de la propiedad  DatsetField del ClienttDataset de detalles que apunta al último campo persistente del ClientDataset maestro.

Finalmente podrás comprobar que al abrir el ClientDataset maestro abre automáticamente el de detalles.

Al aplicar o desechar cambios sobre el maestro guarda o desecha los cambios en los detalles (Talvez sea esta una de las grandes virtudes de esta técnica).

Saludos.

Archivos adjuntos


  • 0

#17 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 14 julio 2009 - 09:40

Definitivamente no es posible de ninguna de las dos formas, cuando se hace de la manera tradicional que tu dices el proveedor ignora el ComandText y lo que hace es crear al vuelo una consulta basada en la setencia SQL del query de detalles  pasando como parámetro el valor actual del campo responsable de la relación de la tabla maestra...


Gracias Wilson, esto aclara muchas cosas y a su vez deja otras dudas, ¿entonces de que manera podrí­a ser esto posible?.

PD: Gracias por el ejemplo.

Saludos!
  • 0

#18 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 14 julio 2009 - 09:57

¿entonces de que manera podrí­a ser esto posible?.

La verdad no veo la necesidad ni lo encuentro práctico hacerlo de la forma que tu lo planteas, basta con que ejecutes el CommandText que propones en el primer procedimiento:


delphi
  1. ClientDataSetCliente.CommandText := 'SELECT * FROM CLIENTE WHERE ID_CLIENTE = ' + Edit1.Text;


y obtienes lo que estás buscando con el CommandText del segundo procedimiento.



delphi
  1. ClientDataSetItem.CommandText := 'SELECT * FROM ITEM WHERE ID_CLIENTE = ' + Edit2.Text;



Saludos
  • 0

#19 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 14 julio 2009 - 10:07

Hola,
Wilson, ¿has probado lo que dices por ti mismo?... te lo digo porque precisamente ha sido todo un problema, da error  :D

Saludos!
  • 0

#20 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 14 julio 2009 - 10:14

Si claro Felipe,  yo se que al ejecutar lo siguiente da error


delphi
  1. ClientDataSetItem.CommandText := 'SELECT * FROM ITEM WHERE ID_CLIENTE = ' + Edit2.Text;



Por eso mismo te digo que lo encuentro innecesario y poco práctico cuando el resultado  que buscas lo obtienes con solo ejecutar



delphi
  1. ClientDataSetCliente.CommandText := 'SELECT * FROM CLIENTE WHERE ID_CLIENTE = ' + Edit1.Text;



Saludos

  • 0




IP.Board spam blocked by CleanTalk.