采用服务器返回数据,一种是返回字符串数据例如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。
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);