采用服务器返回数据,一种是返回字符串数据例如JSON,跨平台跨语言,任何语言调用都支持兼容,类似WEBService。

第二种是紧密结合c++builder语言,传输DataSet,可以是ClientDataSet,也可以是FDMemTable,或TDataSet,这类好处是DataSet本身包含了很多属性,记录集的状态Insert/Modify/Delete,在服务端可以调用

不同的方法进行数据处理,客户端也只需要把dataset对象赋值就展示到dbgrid里了。

序列化。

FDMemTable1有saveToFile(sfJson),虽然是json格式,但不能跨语言交流,只能fdMem.LoadFromFile才可解析。所以用这个json字符串是不通用的,只能RAD delphi/c++使用。

http://localhost:8083/datasnap/rest/TServerMethods1/GetDepartmentNamesJSON

 

一、跨平台纯字符串

 

Tokyo 10.2.2有了TFDBatchMoveJSONWriter

https://community.embarcadero.com/blogs/entry/dataset-mapping-to-json-for-javascript-client-support-in-rad-studio-10-2-2

 

对返回的数据增删改查。对应的方法就是Add/Delete/Update/Query,客户端调用此方法就OK了。

数据集转换依赖于TDBXReader、TDBXCommand、SQLConnection1。不能随意转换dataset为json。有个第三方的库可以转。

Serever

String GetPersonAll()

{

return "";字符串形式的JSON或XML格式

aReader:=aCommand.ExecuteQuery;
Result:=TDBXJSONTools.TableToJSON(aReader,10,True).ToString;

}

Client

String DataSTR=srv->GetPersonAll();

对字符串解析JSON或XML,以DataSet展示就可以。

function TServerMethods1.GetData(SQL: String): String;
var
  aCommand: TDBXCommand;
  aReader: TDBXReader;
begin
  Result := '';
  aCommand := SQLConnection1.DBXConnection.CreateCommand; // 指定 SQLConnection1 连接数据库
  try
    aCommand.Text := SQL; // 指定SQL语句
    aReader := aCommand.ExecuteQuery;
    Result := TDBXJSONTools.TableToJSON(aReader, 10, True).ToString;
  finally
    aCommand.Free;
  end;
end;

 

 用第三方库SuperJson也可以。

 二、DataSet

http://blog.csdn.net/ddqqyy/article/details/6982164 利用TDBXDataSetReader实例化,传输的是TDBXReader

http://blog.csdn.net/ddqqyy/article/details/6174525 讲的是返回dataset ClientDataSet1.Delta,TDataSetProvider,TSqlServerMethod,还用到了OleVariant

#include <Data.DBXCDSReaders.hpp>

 static void __fastcall CopyReaderToClientDataSet(Data::Dbxcommon::TDBXReader* Reader, Datasnap::Dbclient::TClientDataSet* Dataset);
 static Datasnap::Dbclient::TClientDataSet* __fastcall ToClientDataSet(TComponent* AOwner, Data::Dbxcommon::TDBXReader* Reader, bool AOwnsInstance);

C++中这些返回指针,怎么释放一直没想清楚。

 三、返回ClientDataSet1的OleVariant

int TServerMethods1::GetTableDataSet(String atableName, OleVariant adata)
{
   ClientDataSet1->Open();
   adata = this->ClientDataSet1->Data;
   return this->ClientDataSet1->RecordCount;

}

DataSetProvider1也有Data属性。

OleVariant Data

DataSetProvider1->Data;

只能用ClientDataSet1,其他的数据集都没有data属性,有data属性的FDQuery类型也不是OleVariant 。

ClientDataSet:OleVariant Data

FDQuery:_di_IFDDataSetReference Data 

 

四、返回TDBXReader 

TDBXReader  可以自己释放内存,所以不必担心内心释放泄露的问题了。

 #include "Data.DBXCDSReaders.hpp"

TDBXReader* TServerMethods1::GetDSReader(String asql)
{
    TDBXCommand *cmd;
    TDBXReader *reader;
    TClientDataSet *cds;
    cmd = SQLConnection1.DBXConnection.CreateCommand;
    cmd->Text = asql;
    reader = cmd->ExecuteQuery();
return reader;

//or cds
= TDBXClientDataSetReader::ToClientDataSet(NULL, reader, true); return new TDBXClientDataSetReader(cds, true); }

 Client

 reader= CallProxy.GetDSReader();

TDBXClientDataSetReader::CopyReaderToClientDataSet(reader,cds);
cds->Open();

 

五、用ClientDataSet 

服务端:

fdquery

DataSetProvider1.DataSet=fdquery;

DataSetProvider1.Option.poAllowCommandText=true;

客户端

SQLConnection1

TDSProviderConnection.sqlconnection=SQLConnection1

TDSProviderConnection.serverclassname =tServerMethods1

ClientDataSet.RemoteServer=DSProviderConnection1

ClientDataSet.providername =DataSetProvider1

ClientDataSet.open();

ok!

六、返回TFDJSONDataSets 

TFDJSONDataSets可以返回多个数据集。这个是以后的趋势!REST Client,但是这个不能跨语言,客户端只能用RAD的TFDJSONDataSetsReader解析。但依然不能跨语言,C#,java无法解析。
服务的没有释放TFDJSONDataSets总感觉有内存泄漏,调用1000次测试一下。
返回字符串没有内存泄漏。

server
function TServerMethods1.GetJSONData: TFDJSONDataSets;
begin
  Result := TFDJSONDataSets.Create;
  if not FDMemTable1.Active then
    FDMemTable1.LoadFromFile('../../customer.fds')
  else
    FDMemTable1.Active := False;
  TFDJSONDataSetsWriter.ListAdd(Result, FDMemTable1);
end;

 

Client

var
  DSList: TFDJSONDataSets;
begin
  FDMemTable1.Close;
  DSList := ClientModule1.ServerMethods1Client.GetJSONData;
  FDMemTable1.AppendData(
      TFDJSONDataSetsReader.GetListValue(DSList, 0));
  FDMemTable1.Open;
end;

 or serverProxy eg

 FUnMarshal := TDSRestCommand(FGetDepartmentNamesCommand.Parameters[0].ConnectionHandler).GetJSONUnMarshaler;
 Result := TFDJSONDataSets(FUnMarshal.UnMarshal(FGetDepartmentNamesCommand.Parameters[0].Value.GetJSONValue(True)));

客户端 也可以  FDMemTableDepartments.Data := TFDJSONDataSetsReader.GetListValue(LDataSetList, 0);

七、返回TJSONArray


function TServerMethods1.getstr3: TJSONArray;
begin
result:= TJSONObject.ParseJSONValue('[{"name":"张三"}]') as TJsonArray;
end;

八、返回FireDAC TJSONObject

function TServerMethods1.getstr2: TJSONObject;
begin
result:= TJSONObject.ParseJSONValue('{"name":"张三"}') as TJSONObject;
end;

此方法虽然返回了TJSONObject,但依然不能跨语言,C#,java无法解析。

DataSet2JsonObject 

DataSetsToJSONObject
从DataSet到TJsonObject
http://community.embarcadero.com/blogs/entry/cbuilder-xe6-multitier-database-app-with-firedac-json-reflection-40330
TJSONObject * TServerMethods1::GetDepartmentEmployeesJSON     ( System::UnicodeString AID )
{

    FDQueryDepartmentEmployees->Active = false;
    FDQueryDepartment->Active = false;
    FDQueryDepartment->Params->operator[ ]( 0 )->Value = AID;
    FDQueryDepartmentEmployees->Params->operator[ ]( 0 )->Value = AID;
    // Create dataset list
    TFDJSONDataSets * ds = new TFDJSONDataSets( );
    // Add departments dataset
    TFDJSONDataSetsWriter::ListAdd( ds, sDepartment, FDQueryDepartment );
    // Add employees dataset
    TFDJSONDataSetsWriter::ListAdd( ds, sEmployees,
        FDQueryDepartmentEmployees );
    TJSONObject * obj = new TJSONObject( );
    TFDJSONInterceptor::DataSetsToJSONObject( ds, obj );
    return obj;
}

 服务的没有释放TFDJSONDataSets总感觉有内存泄漏,调用1000次测试一下。
返回字符串没有内存泄漏。

TFDJSONDataSets

C++Builder
http://blogs.embarcadero.com/pawelglowacki/2014/06/04/40330/

Delphi
http://blogs.embarcadero.com/fernandorizzato/index.php/2014/07/21/multi-tier-com-delphi-xe6-e-firedac-json-reflection/

http://www.cnblogs.com/hnxxcxg/p/4007876.html
http://www.cnblogs.com/hnxxcxg/p/4008789.html
http://www.kzx123.com/?p=105
http://blog.marcocantu.com/blog/delphi_xe5_update2_datasnap_firedac.html
D:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\Object Pascal\DataSnap\FireDACJSONReflect

 TFDJSONDataSets *dset;
 TFDJSONDataSetsReader * dsread;
 TFDJSONDataSetsWriter::ListAdd(dset, FDMemTable1);//FDQuery1

TFDJSONDataSets 是DataSet的集合,数据集的集合,可以持有多个DataSet。
FDQuery1,FDMemTable1其实也可以有多个数据集,也算是数据集的集合,取下一个数据集FDQuery1.NextRecordSet

  FireDAC默认是不支持多结果集返回的, 需要手动设置 FetchOptions.AutoClose := False;


下面sql返回2个数据集。
FDQuery1.SQL.Text := 'select * from orders; select * from customers';

Data.FireDACJSONReflect.hpp
返回值可以是 TFDJSONDataSets,TJSONObject*,TFDJSONDeltas
通过 TFDJSONInterceptor::DataSetsToJSONObject()把TFDJSONDataSets转为TFDJSONDataSets。
DataSnap 多层返回数据集分析FireDAC JSON
 static bool __fastcall DataSetsToJSONObject(TFDJSONDataSetsBase* const ADataSets, System::Json::TJSONObject* const AJSONObject);
 static bool __fastcall JSONObjectToDataSets(System::Json::TJSONObject* const AJSONObject, TFDJSONDataSetsBase* const ADataSets);
 static int __fastcall ListApplyUpdates(TFDJSONDeltas* const ADeltaList, const System::UnicodeString AKey, Firedac::Comp::Client::TFDCustomCommand* const ASelectCommand, TFDJSONErrors* const AErrors = (TFDJSONErrors*)(0x0))/* overload */;
 static Firedac::Comp::Client::TFDAdaptedDataSet* __fastcall GetListValueByName(TFDJSONDataSets* const ADataList, const System::UnicodeString AName);
View Code

相关文章: