1
votes

Using either Delphi 10.2 or 10.3, FireDAC and either Firebird 2.5 or 3.0: I've used the JVCL TJvAppStorage components for years and never had a problem with them, either to INI/XML storage or to a table in an AbsoluteDB database. I'm trying to migrate an app from AbsoluteDB to Firebird via FireDAC, and can't get the TJvAppDBStorage to write entries - it returns no errors, but nothing actually gets written into the table.

I have a datamodule containing the FireDAC connection and driver components, the JvAppDBStorage, a TDataSource and a TFDTable component. The FDB exists containing an appropriate table, the TFDTable is open on that table, the JvAppDBStorage has its properties set to match the table's fields, and the TFDTable, datasource and JvAppDBStorage are properly linked. (This all mirrors what has existed and worked against AbsoluteDB.) A call to dmStorage.FBStorage.WriteString(dmStorage.FBStorage.ConcatPaths(['General', 'LastStarted']), FormatDateTime(StdDTFmtStr, Now)); does not throw any exceptions, but nothing actually gets written into the table. Doing a normal append/set fields/post construct via the TFDTable works properly.

Any help appreciated! Steve

1
Steve, I'm just wondering what transaction control, if any, gets exerted when TJvAppStorage does its stuff. You might take a look at this article if you haven't already seen it.MartynA
Martyn, you're on to something, I think - TJvAppDBStorage does NO explicit transaction handling. And Firebird is picky about transactions. Thanks for the article reference; I'll dig into this further.Steve Sneed
Followup: Creating a new TFDTransaction object and associating it with the TFDTable being used by the TJvAppDBStorage object eliminates the problem. Trying to share the default transaction object from the TFDConnection won't work, it must be a different instance.Steve Sneed
Glad you''ve found a solution. Why not post it as an answer (it's fine to answer your own qs on SO, and after 2 days you can "accept" them), that way future readers get the benefitMartynA

1 Answers

1
votes

There are 3 critical parts to this:

  1. The underlying table must have a PK. I have an ID column with an associated sequence with before-insert trigger to make an auto-inc column for my PK, and an index that's a merge of the SectionID and KeyID fields to speed up the Locate() calls.

  2. When creating the TFDTable object, you must create a new TFDTransaction object and attach it to the TFDTable and the TFDConnection.

  3. On the TFDTable, you must set UpdateOptions.UpdateMode to upWhereKeyOnly. If you only do the first two steps, reads and appends will work but edits will not.

    function TFDDBMgr.MakeTableObj(const ATblName: String): TFDTable;
    begin
      Result := TFDTable.Create(Self);
      with Result do begin
        //hook up all our needed stuff
        Connection := Self.Connection;
        TableName := ATblName;
        CachedUpdates := False;
        {...}
    
        //!!.SS 09/11/19: REQUIRED for TJvAppDBStorage use, 
        //also requires that a PK be defined on the table
        UpdateOptions.UpdateMode := upWhereKeyOnly; 
        Transaction := TFDTransaction.Create(Result);
        Transaction.Connection := Self.Connection;
      end;
    end;