Скопировать базу данных на привязанный клиент - PullRequest
2 голосов
/ 01 апреля 2019

Я создал привязанное приложение.Сервер должен скопировать Sqlite db и передать его клиенту.

Я получаю db с этим кодом:

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;

Я ловлю поток и записываю db с этим кодом:

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

Спасибо ... Dan'l '+

1 Ответ

2 голосов
/ 01 апреля 2019

Я не думаю, есть способ полностью скопировать базу данных Sqlite на привязанный клиент, если не скопировать весь файл базы данных на клиент, поскольку он может содержать множество таблиц и других ресурсов.например, представления, хранимые процедуры и т. д.

Однако копирование всей базы данных в виде файла на самом деле довольно просто.В клиенте вы можете открыть в нем таблицу с помощью локального 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;

Я проверилвыше в Delphi 10.2.3 на Win10 64-bit, и он прекрасно работает для меня.

Если вы хотите скопировать на клиент только несколько таблиц, я бы сделал

  • На сервере откройте одну из таблиц в FDQuery, затем присвойте ее данные FDMemtable с помощью FDMemTable1.Data := FDQuery1.Data

  • Вызовите SaveToStream для FDMemTable1 и отправьте поток какпотоковый ресурс для клиента

  • На клиенте вызовите FDMemTable.LoadFromStream для загрузки полученного потока.Я думаю , потому что я не пробовал, чтобы клиенту нужно было содержать TFDPhysSQLiteDriverLink для поддержки загрузки из потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...