Briefcases: Request only the changed records for some huge table from the server side


(arturomonge) #1

Hi,

I’m working with briefcase files to store on the client side, tables that do not change often. I keep track of the last update date of these tables on the server, and on startup, I compare those dates to the local dates and decide which tables to reload from the server.

However, I’m now interested in the following use case from this article:

http://blogs.remobjects.com/blogs/jim/2013/02/12/p5613

Request only the changed records for some huge table from the server side and then merge the delta with the client table loaded from the local briefcase.

Do you have any suggestions or samples on how to accomplish this? What I can think of is storing each delta in a table on the server, using the OnBeforeProcessChange event of the table’s business processor. Then, on the client, when I get the table the first time from the server, I’d load the table along with the date of the last known delta. Then, when I refresh the table on the client, I’d compare the dates of the last delta in the client and the server, and if they are different, get the missing deltas and apply them on the client.

Is this the best approach, or is there any other way to achieve this? Also, how do I store a delta in the database, and then apply it to the local data table once I retrieve the delta from the server?

Thanks,
Arturo.


(antonk) #2

Hello

You could also consider a simpler approach:

On the server the table has a trigger-based field that stores for each row the datetime of its last update.
When the time to update the local cache comes the client app requests only the lines with last update dates past the max update data in the local table ant then merges the received data rows (if any) into the local data table


(arturomonge) #3

Thanks, Antonk, this is definitely a much simpler approach. :+1:

Do you have any suggestions on how to do the merge of the new records? I know there is a RefreshFromServer method that will add new records and update modified records, which is basically what I need to do in this case. Is there a way to use a different data call for RefreshFromServer? I’m thinking I could use that to run a query that returns only those records that changed, and then let RefreshFromServer do the rest.

Thanks again,
Arturo.


(antonk) #4

Assuming you are using Delphi: RefreshFromServer uses the GetData call. You should be able to customize it.

If you don’t mind, I’ll redirect your question to our Delphi guru.


(arturomonge) #5

Yes, I’m using Delphi. Thanks!

Arturo.


(EvgenyK) #6

above solution doesn’t take to attention deleted records, so I can suggest updated scenario.

Imagine that your table have 2 additional fields:
Deleted: byte
Updated: timestamp

at start, you load tables from briefcase, create DynamicWhere expression for selecting all records later last synchronization and call table.RefreshFromServer) :

with table.DynamicWhere do begin
  loldExpression := Expression;  // store current expression
  Expression := NewBinaryExpression(table.LogicalName, 'Updated', dboGreater, myLastUpdate, datDateTime); // apply new expression
  try
    table.RefreshFromServer;
  finally
    Expression.Free;
    Expression := loldExpression; // restore default table expression
  end;
end; 

deleted field will indicate that records were deleted so you need to hide it with filters.

Also you can introduce a new event that will be fired by server if any changes are made.
when clients receive it, they should also call RefreshFromServer as above.

You don’t need to use different data call because you can just use DynamicWhere expression.


(John Manchester) #7

Hi
I’m trying to run refresh on briefcase which is working just fine in Delphi project :slight_smile: with something like this:

  procedure TClientDataModule.RefreshBriefcase;
var
  lbriefcaseName: string;
  lbriefcase: TDAFolderBriefcase;
begin
  
  lbriefcaseName := GetBriefcaseFileName;
 
    lbriefcase:= TDAFolderBriefcase.Create(lbriefcaseName,True,True);
    if ValidateBriefcase(lbriefcase) then begin
      GetTablesFromBriefcase(lbriefcase);
    end;

end;

same idea in .NET throwing an error :

A DataTable named ‘Products’ already belongs to this DataSet

public void RefreshBriefcase()
        {
            String briefcaseName = this.BriefcaseFileName;
            this.AddToLog(String.Format("Briefcase: {0}", briefcaseName));
 
                Briefcase briefcase = new FolderBriefcase(briefcaseName);
                briefcase.ReadBriefcase();
                Boolean valid = this.ValidateBriefcase(briefcase);
                if (valid)
                {
                    this.GetTablesFromBriefcase(briefcase);
                }
        }

What can be wrong with .NET version?

Best regards
John


(antonk) #9

Hello

Could you send this briefcase to support@ so we’ll be able to reproduce this issue locally?

Thanks in advance