我创建了一个共享应用程序。服务器需要复制一个Sqlite数据库 并将其流式传输到客户端。
我用以下代码获取数据库:
procedure TfmxServer.actStreamTheDbExecute(Sender: TObject);
var
ms: TMemoryStream;
begin
ms := tmemorystream.Create;
ms := dmplanner.GetDbAsStream; // get it from the datamodule
ms.Position := 0;
thrprofServer.SendStream(thrmanServer.RemoteProfiles.First,
'Stream_TheDB', ms); // send it to the client
end;
function TdmPlanner.GetDbAsStream: TMemoryStream; // datamodule
var
fs: TFilestream;
ms: TMemoryStream;
begin
fs := tfilestream.Create(consqlite.Params.Values['Database'] , fmOpenRead);
ms := tmemorystream.Create;
try
ms.loadfromstream(fs); // ms.size = 315392, file size = (315,392 bytes
result := ms; // so I am getting the full db3 file.
result.Position := 0;
finally
freeandnil(fs);
freeandnil(ms); // does this kill the result?
end;
end;
我捕获了流,并使用以下代码编写了数据库:
procedure TfrmMobile_Client_Main.DoStreamTheDb(
const Aresource: TremoteResource);
var
fs: TFilestream;
ms: TMemoryStream;
begin
fs := tfilestream.Create
(dmplannerclient.consqlite.Params.Values['Database'] ,
fmopenreadwrite or fmCreate);
try
ms := TMemoryStream.Create;
ms := TMemoryStream(AResource.Value.AsStream);
ms.Position := 0; // ms.size = 315392, so I got the whole file.
ms.SaveToStream(fs);
dmPlannerClient.FillLbx(lbxRecipeNames);
// now fill a listbox, but when I open a query, I get
// [FireDAC][Phys][SQLite] ERROR: unable to open database file.
finally
freeandnil(fs);
freeandnil(ms);
end;
end;
所以我的问题是,如何将数据库复制到客户端 然后在客户端上使用它?
更好的是,如何使用内存数据库而不是磁盘数据库? 我尝试将FDConnection文件名设置为:memory:,但这 没用。
Delphi CE Rio 10.3.2
谢谢...丹尼尔+
答案 0 :(得分:2)
我不认为有一种方法可以将整个Sqlite数据库复制到绑定的数据库中 缺少将整个数据库文件复制到客户端的客户端,因为它可能包含 许多表格和其他资源(例如视图,存储的proc等)。
但是,实际上将整个数据库复制为文件 很简单。在客户端中,您可以使用本地FDConnection在其中打开表 和FDQuery。
服务器代码:
procedure TApp1Form.SendDBAsStream;
var
StreamToSend : TMemoryStream;
const
DBName = 'D:\Delphi\Code\Sqlite\DB1.Sqlite';
begin
StreamToSend := TMemoryStream.Create;
try
StreamToSend.LoadFromFile(DBName);
StreamToSend.Position := 0;
TetheringAppProfile1.Resources.FindByName('SqliteDB').Value := StreamToSend;
finally
// Don't free StreamToSend ?
end;
end;
客户代码
procedure TApp2Form.TetheringAppProfile1Resources0ResourceReceived(const Sender:
TObject; const AResource: TRemoteResource);
var
ReceivedStream : TStream;
FileStream : TFileStream;
begin
FileName := ExtractFilePath(Application.ExeName) + 'Temp.Sqlite';
AResource.Value.AsStream.Position := 0;
FileStream := TFileStream.Create(FileName, fmCreate);
ReceivedStream := AResource.Value.AsStream;
try
ReceivedStream.Position := 0;
FileStream.CopyFrom(ReceivedStream, ReceivedStream.Size);
finally
FileStream.Free;
// ReceivedStream.Free; No! The tethering framework frees the stream
end;
OpenTable;
end;
procedure TApp2Form.OpenTable;
begin
if FDConnection1.Connected then
FDConnection1.Connected := False;
FDConnection1.Params.Clear;
FDConnection1.Params.Add('Database=' + FileName);
FDConnection1.DriverName := 'Sqlite';
try
FDConnection1.Connected := True;
FDQuery1.Open('select * from mytable');
except
ShowMessage(Exception(ExceptObject).Message + ' ' + FileName);
end;
end;
我在Win10 64位的Delphi 10.2.3中测试了上述内容,对我来说很好用。
如果您只想将几个表复制到客户端,我会做的是
在服务器中,打开FDQuery中的表之一,然后将其数据分配给
FDM可由FDMemTable1.Data := FDQuery1.Data
在FDMemTable1上调用SaveToStream并将流作为流资源发送到客户端
在客户端上,调用FDMemTable.LoadFromStream以加载接收到的流。我认为, 因为我还没有尝试过客户端需要包含一个TFDPhysSQLiteiteDriverLink 支持从流中加载。