PDA

Ver la Versión Completa : Pasar objetos entre Cliente y Servidor


Jere_84
07-06-2012, 00:31:34
Hola Club, En mi aplicación Datasnap quiero hacer una función del lado servidor que tome como parámetro un objeto tipo TClientDataSet y otro tipo TField, el problema es que aparentemente y no se bien el porque pero así parece en la ayuda Delphi, solo soporta entre las capas los siguientes tipos de datos, algo que resulta bastante limitado.

Boolean, SmallInt, Integer, Int64 ,Single ,Double ,AnsiString ,String ,
TDBXTime ,TDBXDate ,TJSONValue and all descendents ,TDBXWideStringValue ,TDBXAnsiStringValue, TDBXUInt8Value ,TDBXInt8Value ,TDBXInt16Value ,TDBXInt32Value ,TDBXInt64Value ,TDBXSingleValue ,TDBXDoubleValue ,TDBXBcdValue ,TDBXTimeValue ,TDBXDateValue
TDBXTimeStampValue ,TDBXBooleanValue ,TDBXReaderValue ,TDBXStreamValue

los siete primeros tipos son familiares pero los tipo TDBX, resultan nuevos para mi y estan relacionados con DBEXPRESS, ademas aparecen como clases.
¿Alguno de ustedes ha utilizado este tipo de datos?
¿Alguien tiene alguna sugerencia de como podría pasar objetos entre las dos capas?

Cualquier información referida es bienvenida.
Utilizo Delphi 2010.
Quizás en las versiones XE y XE2 esto se halla ampliado (que lo digan los usuarios de estas versiones).

mamcx
07-06-2012, 01:14:23
Para pasar mensajes por fuera del proceso de un ejecutable (osea, lo que esta en memoria en tu programa) con capacidad de operar en internet se necesita serializar/deserializar las cosas.

http://es.wikipedia.org/wiki/Serializaci%C3%B3n

Piensa que el mundo exterior a tu ejecutable no es delphi, ergo, no entiende los tipos de datos y funciones de delphi. Aunque te comuniques Delphi=>Delphi no hay una forma de decir "Hey, haz de cuenta que corremos en el mismo espacio de memoria, asi tu estes en nigeria!".

Asi que hay que traducir un objeto en un formato simplificado.

Por ejemplo, si una clase:


Persona = TPersona
Nombre:String;

Persona.Nombre := 'mamcx';


Entonces se pasaria en un formato como json, xml, binario, o ini como este caso:


[TPersona]
Nombre=mamcx


Entre ambos procesos.

El que se pueda enviar TDBXTime y demas es solo porque esas clases tienen definido su codigo de serializacion/deserializacion. Osea, realmente NO ESTAS PASANDO EL OBJETO, estas pasando los datos que permiten recrear el objeto en el otro lado.

Entonces, debes es convertir tu objeto delphi en un formato que ambos extremos entiendan, como por ejemplo:

(Esto es un caso GENERICO)
http://stackoverflow.com/questions/368913/whats-a-good-way-to-serialize-delphi-object-tree-to-xml-using-rtti-and-not-cus

y luego en el extremo que recibe el formato, creas un objeto TClientDataSet, y le metes esos valores.

----

AFORTUNADAMENTE ClientDataset permite guardar datos en un stream/xml:

http://stackoverflow.com/questions/3848853/using-delphi7-tclientdataset-is-it-possible-to-have-it-save-its-xml-contents-i

ClientDataSet1.SaveToFile('file.xml',dfXML);
//Cargas el archivo en un string y lo envias aqui


Defines que el servidor pasa datos string.

y usas el metodo de LoadFromFile en el otro extremo. Listo

Jere_84
07-06-2012, 13:58:52
ClientDataSet1.SaveToFile('file.xml',dfXML);
//Cargas el archivo en un string y lo envias aqui


Defines que el servidor pasa datos string.

y usas el metodo de LoadFromFile en el otro extremo. Listo[/QUOTE]

Hola, muchas gracias por la respuesta gracias. guiame un poco como sera esto de cargar el un archivo xml. ya que no tengo experiencia en este lenguaje. Del lado servidor lo que tengo es esto por ejemplo:


function TPLDBVALIDACION.DatoVacio(oClientDataSet: TCustomClientDataset; var oCampo: TField): boolean;
begin
// ...
end;


Esta función la llamaría desde el lado cliente al generar la clase cliente atreves del componente SQLConnection obviamente que esto no es posible ya que este tipo de datos (TCustomClientDataset y TField) no son soportados, por lo tanto como lo arias de la forma que vos me recomendaste?

Slds.

Jere_84
07-06-2012, 23:27:10
Estuve probando el procedimiento y va bien pero al instante de hacer el LoadFromFile me da una excepción donde enuncia que no se puede abrir el archivo "C:\Users\..." (toda la ruta exacta en donde esta ubicado). Luego formula: El sistema no puede encontrar el archivo especificado. todo en la misma notificación. pero resulta raro que no lo localize siendo que la dirección que figura es exacta.


vClientDataSet:= TCustomClientDataset.Create(nil);
vClientDataSet.LoadFromFile(archivo); <----------------- Acá.
vClientDataSet.Open;

StartKill
08-06-2012, 01:13:03
Hola Jere_84
Vamos a guiarnos por la sugerencia de mamcx, que está muy buena

Antes de nada unas palabras...: "El poderoso Datasnap que acorta distancias" :)

Jere_84 dice:
Hola Club, En mi aplicación Datasnap quiero hacer una función del lado servidor que tome como parámetro un objeto tipo TClientDataSet y otro tipo TField, el problema es que aparentemente y no se bien el porque pero así parece en la ayuda Delphi, solo soporta entre las capas los siguientes tipos de datos, algo que resulta bastante limitado. .....


mamcx responde a la duda, solo vamos tomar la solución que él dá: (al margen de la explicación que nos dió, corta y buena)

AFORTUNADAMENTE ClientDataset permite guardar datos en un stream/xml:

http://stackoverflow.com/questions/3...xml-contents-i

ClientDataSet1.SaveToFile('file.xml',dfXML);
//Cargas el archivo en un string y lo envias aqui
Defines que el servidor pasa datos string.

y usas el metodo de LoadFromFile en el otro extremo. Listo


Haciendo mas fácil esto:
En el lado cliente de tu aplicativo Datasnap

procedure TForm13.Button1Click(Sender: TObject);
var
f: TextFile;
xml, line: string;
fileName: string;
begin
fileName:= ExtractFilePath( Application.ExeName ) + 'datos.xml';
ClientDataSet1.Open;
ClientDataSet1.SaveToFile(fileName, dfXML);
AssignFile(f, fileName);
// podrias mejorar la lectura del archivo en un objeto memo
reset(f);
while not Eof(f) do
begin
ReadLn(f, line);
xml := xml + line;
end;
closeFile(f);
//-----
//....
xxxxx.carga(xml); //llamas a tu método en el server;
end;


En el lado server el método que recepciona los datos debria ser mas o menos asi:

procedure TServerMethodsServerProductos.carga(xml: string);
var
f: TextFile;
fileName: string;
begin
fileName:= ExtractFilePath( Application.ExeName ) + 'dstos.xml';
AssignFile(f, fileName);
Rewrite(f);
Write(f, xml);
closeFile(f);
ClientDataSet2.close;
ClientDataSet2.LoadFromFile(fileName);
ClientDataSet2.Open;
end;

Espero que sirva de algo el código...


Your friend

StartKill
Lima-Perú

Jere_84
08-06-2012, 14:45:44
Hola StartKill. Gracias por el código :) ¿Esto anda si mi aplicación cliente y servidor se alojan en distintas terminales de una red? o ¿En el caso de que estén conectadas por internet, en redes distintas?