Briefcase sample (console) (Delphi)

The Briefcase sample demonstrates using the TDAFileBriefcase class to store and then load two TDADataTables that have changes that are waiting to be sent to the server.

A Briefcase can be helpful for situations where there isn't a persistent connection to the server and the user needs to be able to quit your app or otherwise work in an offline fashion. Another use of a it might be to aid in the application start-up process, as you can load the data from disk without needing to rely on the server being available.

Getting Started

The sample is located in C:\Users\Public\Documents\RemObjects Samples\Data Abstract for Delphi\Briefcase (Console).

To build it, you will need Delphi Rad Studio, and like all the samples provided with Data Abstract for Delphi you will need to be running Relativity Server with the DASamples Domain and the Simple Schema available.

Included with the sample is a uLogSupport class which has a LogTable procedure that takes an instance of TDADataTable and creates a nicely formatted string representation of the table that it then prints to the Console which can be useful for debugging purposes. (An example of its output can be seen at the end of this document)

Running the Sample

The sample when run sets up a connection to an instance of Relativity Server (STEP 1) and then retrieves a limited set of data from two TDADataTables using a DA SQL statement to do the filtering (STEP 2). The first table is the Orders table, where we are only interested in the rows that match particular order ids. The second table is the OrderDetails table, where we are only interested in the rows where the value in the Order column matches the order id.

Having retrieved the tables, we make minor modifications to them so that they are different than the server versions so we can see see that when we reload the data from the briefcase; specifically we increase the value in the Amount column of the OrderDetails table (STEP 3). The newly modified tables are then saved to disk in a briefcase file with some properties set that will be printed when the briefcase is later reloaded (STEP 4).

The briefcase is then reloaded from disk and the contents printed to the console (STEP 5), before the changes are then applied back to the server and stored to disk once again.

Once the sample is finished if you navigate to the C:\Users\Public\Documents\RemObjects Samples\Data Abstract for Delphi\Briefcase (Console)\ folder in Explorer, you will see the briefcase file (BriefcaseSample.daBriefcase) that was written to disk at the end of the samples run. That single file contains the two Data Tables and the briefcase properties and if you double click on it the Briefcase Explorer will open and display the contents of the briefcase for examination.

Examining the Code

The code for creating the connection to the server, retrieving and modifying the data are covered by other samples; for instance DA SQL. In this section we shall focus solely on steps 4 and 5 that handle the creation of the briefcase, storing the tables in it and then reloading those tables back from disk.

Store the tables in a new briefcase

As noted in the Briefcase Overview, briefcases can be stored in one of two formats; either as a single .daBriefcase which will contain all of the tables and properties that you set or as a package (folder) where each table is stored in its own .daBriefcase file and the properties are stored in a .plist file. This sample uses the single file version, but if you want folder format simply replace the two instances of TDAFileBriefcase with TDAFolderBriefcase.

The Create constructor for TDAFileBriefcase used in this sample takes three arguments, although other variants are available. The first argument is a string which will be used as the filename and location to store the briefcase file. If the filename is simply a filename specified without a location, then the briefcase will be stored in the folder in which the sample is being run, otherwise the TDAFileBriefcase will attempt to store the file in the specified location. The second argument is a boolean which indicates if the TDAFileBriefcase should deserialize its contents immediately on opening, this allows you to do lazy loading which can save memory. As we intend to only store contents in the briefcase wiping out anything that was stored there before, we pass in false. The final argument informs the class who should be the owner of the tables stored inside it.

Properties are stored in a property object, to see a property we specify the property name and then the value to assign to that property. This sample sets two properties, the first will be used to store the date when the briefcase is updated, and the second argument is a version number which could be used to prevent loading a briefcase from an old version of the application.

To add a table to the briefcase, use the AddTable procedure which takes a TDADataTable as the first argument and a boolean to indicate if the contents of the table should be copied. This adds the table to the briefcase and if a table with the same name is already there, it will be replaced with this new table.

At this stage, the tables only exist in the briefcase in memory, to store the briefcase on disk the WriteBriefcase procedure to actually write it to the filesystem.

Log('STEP 4. Prepare briefcase and store tables there ...');
lbr := TDAFileBriefcase.Create(BRIEFCASE_FILENAME,False,False);
try
  lbr.PropValues['UpdateDate'] :=  '';
  lbr.PropValues['Version']:= BRIEFCASE_VERSION;
  Log('Briefcase: '+ExtractFilePath(ParamStr(0))+ lbr.FileName);
  Log('Added tables: OrderDetails, Orders');
  lbr.AddTable(ltable1,False);
  lbr.AddTable(ltable2,False);

  Log('Writting briefcase to file system ...');
  lbr.PropValues['UpdateDate'] :=  DateTimeToStr(Now);
  lbr.WriteBriefcase;
finally
  lbr.Free;
end;

Loading the briefcase from disk and retrieving the tables

As before we pass the BRIEFCASE_FILENAME to the TDAFileBriefcase constructor along with two boolean arguments. The first True indicates that the data should be pre-loaded, and the second indicates who owns the tables.

The briefcase is loaded back into memory from disk, and we can immediately start retrieving the properties and tables that were stored in it. Properties are retrieved by passing the name of the property to PropValues[], and a copy of the stored TDADataTable is retrieved using the FindTable function.

Here we retrieve the Version and UpdateDate properties and print them to the console and then it loops through each table stored in the briefcase using the TableCount property, printing each table to the console and showing that each table still has the modifications made in Step 3.

Log('STEP 5. Read briefcase from file system with its pending changes ...');
lbr := TDAFileBriefcase.Create(BRIEFCASE_FILENAME,True,True);
try
  Log('Briefcase version is: '+lbr.PropValues['Version']);
  Log('Briefcase update date is: '+lbr.PropValues['UpdateDate']);
  Log();
  for i := 0 to lbr.TableCount - 1 do begin
    LogTable(lbr.FindTable(i));
    Log();
  end;

  Log('Apply pending changes to the server and update briefcase ...');
  // extract content of tables
  lbr.Fill([ltable1,ltable2]);
  lRemoteDataAdapter.ApplyUpdates([ltable1,ltable2]);
  lbr.AddTable(ltable1,True);
  lbr.AddTable(ltable2,True);
  lbr.WriteBriefcase;
finally
  lbr.Free;
end;

Typical Output

This is a typical output from the sample after it has been run. As you can see it clearly calls out each step as it is processed. You can see that the values in the Amount column are increased by 1 between when they are first retrieved from the server in Step 2 and when they are loaded back from the briefcase in Step 5.

Briefcases

:Briefcase sample has been started.
Target URL is http://localhost:7099/bin
RO DataAbstract layer is configured.

STEP 1: Login to DataService

Connecting to Relativity server: http://localhost:7099/bin
Login string is :
  User Id="simple";Password="simple";Domain="DASamples";Schema="Simple"
Login has been successfull. Going further...

STEP 2. Select some data (certain orders and their details) to store as briefcase ...

Table: Orders (3 rows from 3)
-----------------------------------------------------------------------
| Id   | Date                | Status | Type   | Contractor | Manager |
-----------------------------------------------------------------------
| 20   | 03/01/2014 12:48:55 | 0      | 2      | 21         | 8       |
| 22   | 03/01/2014 15:57:42 | 0      | 2      | 22         | 8       |
| 24   | 04/01/2014 13:02:24 | 0      | 2      | 22         | 8       |
-----------------------------------------------------------------------

Table: OrderDetails (5 rows from 5)
-----------------------------------------------------
| Id   | Order | Product | Amount | Price           |
-----------------------------------------------------
| 129  | 20    | 79      | 1      | 357             |
| 132  | 22    | 16      | 2      | 360             |
| 135  | 24    | 37      | 2      | 23              |
| 136  | 24    | 24      | 2      | 347             |
| 137  | 24    | 86      | 1      | 17              |
-----------------------------------------------------

STEP 3. Make some changes but does not apply them ...

Table: Orders (3 rows from 3)
-----------------------------------------------------------------------
| Id   | Date                | Status | Type   | Contractor | Manager |
-----------------------------------------------------------------------
| 20   | 03/01/2014 12:48:55 | 0      | 2      | 21         | 8       |
| 22   | 03/01/2014 15:57:42 | 0      | 2      | 22         | 8       |
| 24   | 04/01/2014 13:02:24 | 0      | 2      | 22         | 8       |
-----------------------------------------------------------------------

Table: OrderDetails (5 rows from 5)
-----------------------------------------------------
| Id   | Order | Product | Amount | Price           |
-----------------------------------------------------
| 129  | 20    | 79      | 2      | 357             |
| 132  | 22    | 16      | 3      | 360             |
| 135  | 24    | 37      | 3      | 23              |
| 136  | 24    | 24      | 3      | 347             |
| 137  | 24    | 86      | 2      | 17              |
-----------------------------------------------------

STEP 4. Prepare briefcase and store tables there ...
Briefcase: C:\Users\Public\Documents\RemObjects Samples\Data Abstract for Delphi\Briefcase (Console)\BriefcaseSample.daBriefcase
Added tables: OrderDetails, Orders
Writting briefcase to file system ...

STEP 5. Read briefcase from file system with its pending changes ...
Briefcase version is: v.0.1
Briefcase update date is: 02/06/2016 13:50:37

Table: Orders (3 rows from 3)
-----------------------------------------------------------------------
| Id   | Date                | Status | Type   | Contractor | Manager |
-----------------------------------------------------------------------
| 20   | 03/01/2014 12:48:55 | 0      | 2      | 21         | 8       |
| 22   | 03/01/2014 15:57:42 | 0      | 2      | 22         | 8       |
| 24   | 04/01/2014 13:02:24 | 0      | 2      | 22         | 8       |
-----------------------------------------------------------------------

Table: OrderDetails (5 rows from 5)
-----------------------------------------------------
| Id   | Order | Product | Amount | Price           |
-----------------------------------------------------
| 129  | 20    | 79      | 2      | 357             |
| 132  | 22    | 16      | 3      | 360             |
| 135  | 24    | 37      | 3      | 23              |
| 136  | 24    | 24      | 3      | 347             |
| 137  | 24    | 86      | 2      | 17              |
-----------------------------------------------------

Apply pending changes to the server and update briefcase ...
Done!
Cleanup!

Press Return to exit...