Mar*_*lot 5 delphi datasnap firedac delphi-10.1-berlin
我有一个Delphi 10.1 Berlin Datasnap Server,它不能返回大于260.000字节的数据包(通过TStream).
我在Delphi 的\ Object Pascal\DataSnap\FireDAC示例之后编写了它,它也显示了这个问题.
只需打开该示例,在ServerMethodsUnit.pas上将qOrders组件的IndexFieldName设置为空白,并将其SQL属性更改为:
select * from Orders
union
select * from Orders
Run Code Online (Sandbox Code Playgroud)
现在要发送的数据量超过260.000字节,这似乎是您无法从客户端检索它的点.获得EFDException [FireDAC] [Stan] -710.二进制存储格式无效.
数据作为Stream从服务器上的FDSchemaAdapter获取,然后加载到客户端上的另一个FDSchemaAdpater.客户端和服务器之间的连接也是FireDAC.
这是服务器返回该流的方式:
function TServerMethods.StreamGet: TStream;
begin
Result := TMemoryStream.Create;
try
qCustomers.Close;
qCustomers.Open;
qOrders.Close;
qOrders.Open;
FDSchemaAdapter.SaveToStream(Result, TFDStorageFormat.sfBinary);
Result.Position := 0;
except
raise;
end;
end;
Run Code Online (Sandbox Code Playgroud)
这就是客户端检索它的方式:
procedure TClientForm.GetTables;
var
LStringStream: TStringStream;
begin
FDStoredProcGet.ExecProc;
LStringStream := TStringStream.Create(FDStoredProcGet.Params[0].asBlob);
try
if LStringStream <> nil then
begin
LStringStream.Position := 0;
DataModuleFDClient.FDSchemaAdapter.LoadFromStream(LStringStream, TFDStorageFormat.sfBinary);
end;
finally
LStringStream.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
客户端无法获取Blob参数的所有数据.我在服务器上保存Stream的内容,以及在客户端上到达Blob参数的内容,并且它们具有相同的大小,但Blob参数的内容的内容被截断,最后几个Kbytes为零.
这就是我在服务器上保存将转到Stream的内容的方法:
FDSchemaAdapter.SaveToFile('C:\Temp\JSON_Server.json', TFDStorageFormat.sfJSON);
Run Code Online (Sandbox Code Playgroud)
这是我检查客户端blob参数的方法:
TFile.WriteAllText('C:\Temp\JSON_Client.json', FDStoredProcGet.Params[0].asBlob);
Run Code Online (Sandbox Code Playgroud)
我可以看到客户端获取截断的数据.
您知道如何修复它,或者从Datasnap Server检索所有Stream内容到我的客户端的解决方法吗?
更新:我已更新到Delphi 10.1 Berlin Update 2,但问题仍然存在.
谢谢.
我已经编写了一个解决方法。由于我无法传递大于 255Kb 的数据,因此我将其拆分为不同的 255Kb 数据包并单独发送(我还添加了压缩以最小化带宽和往返次数)。
在服务器上,我已将 StremGet 更改为两个不同的调用:StreamGet 和 StreamGetNextPacket。
function TServerMethods.StreamGet(var Complete: boolean): TStream;
var Data: TMemoryStream;
Compression: TZCompressionStream;
begin
try
// Opening Data
qCustomers.Close;
qCustomers.Open;
qOrders.Close;
qOrders.Open;
// Compressing Data
try
if Assigned(CommStream) then FreeAndNil(CommStream);
CommStream := TMemoryStream.Create;
Data := TMemoryStream.Create;
Compression := TZCompressionStream.Create(CommStream);
FDSchemaAdapter.SaveToStream(Data, TFDStorageFormat.sfBinary);
Data.Position := 0;
Compression.CopyFrom(Data, Data.Size);
finally
Data.Free;
Compression.Free;
end;
// Returning First 260000 bytes Packet
CommStream.Position := 0;
Result := TMemoryStream.Create;
Result.CopyFrom(CommStream, Min(CommStream.Size, 260000));
Result.Position := 0;
// Freeing Memory if all sent
Complete := (CommStream.Position = CommStream.Size);
if Complete then FreeAndNil(CommStream);
except
raise;
end;
end;
function TServerMethods.StreamGetNextPacket(var Complete: boolean): TStream;
begin
// Returning the rest of 260000 bytes Packets
Result := TMemoryStream.Create;
Result.CopyFrom(CommStream, Min(CommStream.Size - CommStream.Position, 260000));
Result.Position := 0;
// Freeing Memory if all sent
Complete := (CommStream.Position = CommStream.Size);
if Complete then FreeAndNil(CommStream);
end;
Run Code Online (Sandbox Code Playgroud)
CommStream:TStream 在 TServerMethods 上被声明为私有。
客户端以这种方式检索它:
procedure TClientForm.GetTables;
var Complete: boolean;
Input: TStringStream;
Data: TMemoryStream;
Decompression: TZDecompressionStream;
begin
Input := nil;
Data := nil;
Decompression := nil;
try
// Get the First 260000 bytes Packet
spStreamGet.ExecProc;
Input := TStringStream.Create(spStreamGet.ParamByName('ReturnValue').AsBlob);
Complete := spStreamGet.ParamByName('Complete').AsBoolean;
// Get the rest of 260000 bytes Packets
while not Complete do begin
spStreamGetNextPacket.ExecProc;
Input.Position := Input.Size;
Input.WriteBuffer(TBytes(spStreamGetNextPacket.ParamByName('ReturnValue').AsBlob), Length(spStreamGetNextPacket.ParamByName('ReturnValue').AsBlob));
Complete := spStreamGetNextPacket.ParamByName('Complete').AsBoolean;
end;
// Decompress Data
Input.Position := 0;
Data := TMemoryStream.Create;
Decompression := TZDecompressionStream.Create(Input);
Data.CopyFrom(Decompression, 0);
Data.Position := 0;
// Load Datasets
DataModuleFDClient.FDSchemaAdapter.LoadFromStream(Data, TFDStorageFormat.sfBinary);
finally
if Assigned(Input) then FreeAndNil(Input);
if Assigned(Data) then FreeAndNil(Data);
if Assigned(Decompression) then FreeAndNil(Decompression);
end;
end;
Run Code Online (Sandbox Code Playgroud)
现在效果很好。
| 归档时间: |
|
| 查看次数: |
1173 次 |
| 最近记录: |