#1 2011-03-25 16:04:54

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

OnUpdateEvent and client

I use OnUpdateEvent on server application to know when (and where) the database is update from a client. Then I use a TCP/IP connection between server and clients to upgrade all clients GUI (data inside grids).

Is there a way on OnUpdateEvent to know the client (ip address) who have upgrade the database? In alternative I need send TCP/IP  refresh request from server to ALL clients (also the client that have made the data update).

Offline

#2 2011-03-26 08:49:32

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

Don't rely on OnUpdateEvent.
It's not 100% times called in case of update. Just called on pure REST PUT/POST.

See the updated documentation, about client refresh.
There is no "push" of a refresh command from Server to Client.
It's up to the client to check if the data has been refreshed.
This is what a stateless mechanism expect, and right for a GUI program.

Offline

#3 2011-03-26 12:10:43

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

Re: OnUpdateEvent and client

Yes I know there is no "push" of a refresh command from Server to Client. In fact I use Indy component to create it, when OnUpdateEvent is call on server, the server send a message to all clients, the client read the message and the decide which grid need of an update and ask them to server.

I just have read the documentation, I have found information about UpdateFromServer but I not sure I have understand how use it:
1) I can use a Timer component in client to call some UpdateFromServer;
2) For any UpdateFromServer I can use a code like it: UpdateFromServer([TSQLExample], refreshed); with TSQLExample the table that I need know if update and "refreshed" a boolean variable, if "refreshed" is TRUE the "Example" table is update so my client need to update the GUI, right?

If "refreshed" is TRUE the "Example" table is update from last client requset of the "Example" table?

Questions:
1) updated compared to what?
2) from documentation I see that I can use UpdateFromServer both with TSQLTableJSON and TSQLRecord. How can I use TSQLTableJSON;
3) is this method fast?

thanks

Offline

#4 2011-03-26 12:37:10

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

1) compared to the latest version from server side

2) use TSQLTableJSON instance as parameter to UpdateFromServer

3) it is fast in practice - but I didn't test it on slow network

Offline

#5 2011-03-26 17:53:45

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

Re: OnUpdateEvent and client

Consider this code:

  TSQLTestTable = class(TSQLRecord)
  private
    fTest1: Integer;
    fTest2: RawUTF8;
    fTest3: TSQLRawBlob;
  published
    property Test1: Integer read fTest1 write fTest1;
    property Test2: RawUTF8 read fTest2 write fTest2;
    property Test3: TSQLRawBlob read fTest3 write fTest3;
  end;

now I can use UpdateFromServer from client:

procedure TMainForm.Timer1(Sender: TObject);
var
  ref: boolean;
begin
  if not Database.UpdateFromServer(TSQLTestTable, ref) then
    begin
      MessageBox(Handle, 'Update From Server Error.', 'Test', MB_OK + MB_ICONSTOP);
      Exit;
    end
  else
    begin
      if ref then
        begin
          // the client refresh all GUI about TSQLTestTable.
        end;   
    end;
end;

If the previous code is right, I don't understand how the Server can decide the "type of response", how the server can know if the TestTable table is change from last "client refreshed GUI about TSQLTestTable"? This is my problem, and for reason I cannot understand how use UpdateFromServer.
I'm thinking that I need code like this:

procedure TMainForm.Timer1(Sender: TObject);
var
  ref: boolean;
  tt: TSQLTestTable;
begin
  tt := TSQLTestTable.Craete;
  tt.ID := 1;
  tt.Test1 := 10;
  tt.Test2 := 'words';
  tt.Test3 := ...something...

  if not Database.UpdateFromServer(tt, ref) then
    begin
      MessageBox(Handle, 'Update From Server Error.', 'Test', MB_OK + MB_ICONSTOP);
      Exit;
    end
  else
    begin
      if ref then
        begin
          // the client refresh all GUI about TSQLTestTable.
        end;   
    end;
end;

so the server can compare tt record with database record. This is more logical but also much slower, I should call UpdateFromServer for all records of all table of my database, so I think reasoning is not correct.

Last edited by array81 (2011-03-26 17:54:50)

Offline

#6 2011-03-27 08:15:28

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

If you want to understand how UpdateFromServer works, just take a look at its source code.

function TSQLRestClientURI.UpdateFromServer(const Data: array of TObject; out Refreshed: boolean;
  PCurrentRow: PInteger): boolean;
// notes about refresh mechanism:
// - if server doesn't implement InternalState, its value is 0 -> always refresh
// - if any TSQLTableJSON or TSQLRecord belongs to a TSQLRestServerStatic,
// the Server stated fInternalState=cardinal(-1) for them -> always refresh
var i: integer;
    State: cardinal;
    Resp: RawUTF8;
    T: TSQLTableJSON;
    TRefreshed: boolean; // to check for each Table refresh
const TState: array[boolean] of TOnTableUpdateState = (tusNoChange,tusChanged);
begin
  result := self<>nil;
  Refreshed := false;
  if not result then
    exit; // avoid GPF
  State := ServerInternalState; // get revision state from server
  for i := 0 to high(Data) do
    if Data[i]<>nil then
    if TObject(Data[i]).InheritsFrom(TSQLTableJSON) then begin
      T := TSQLTableJSON((Data[i]));
      if (T.QuerySQL<>'') and (T.InternalState<>State) then begin // refresh needed?
        with URI(Model.Root,'GET',@Resp,nil,@T.QuerySQL) do
          if Lo=200 then begin // GET with SQL sent
            if Assigned(OnTableUpdate) then
              OnTableUpdate(T,tusPrepare);
            TRefreshed := false;
            if not T.UpdateFrom(Resp,TRefreshed,PCurrentRow) then
              result := false else // mark error retrieving new content
              T.fInternalState := Hi;
            if TRefreshed then
              Refreshed := true;
            if Assigned(OnTableUpdate) then
              OnTableUpdate(T,TState[TRefreshed]);
          end
          else result := false; // mark error retrieving new content
        end;
    end else
    if TObject(Data[i]).InheritsFrom(TSQLRecord) then
    with TSQLRecord(Data[i]) do
      if (fID<>0) and (InternalState<>State) then begin // refresh needed?
        if not Refresh(fID,TSQLRecord(Data[i]),Refreshed) then
          result := false; // mark error retrieving new content
      end;
end;

So it will use:

1) internal revision state of the DB; that is, if only SELECT SQL statement have been made, no need to refresh; this will speed up most refresh, because you write much less in the database than you wrote in it.

2) for TSQLRecord, it will call TSQLRestClientURI.Refresh method to retrieve the new record content from server, and compare with the actual content. Refreshed will be set to TRUE if it changed.

3) for TSQLTableJSON, it will call TSQLTableJSON.UpdateFrom method to retrieve the new table content from server, and compare with the actual content. Refreshed will be set to TRUE if it changed.

On practice, this is pretty fast.

I would be able to implement some faster mechanism (based on hash comparison supplied by client) if you need such refresh to be faster in a database which is often written, over a slow network.

But first check how it works, and then tell me if it's too slow for your need.

Offline

#7 2011-03-27 09:58:50

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

Re: OnUpdateEvent and client

I had read the source, my question is derived it. From what I understand with UpdateFromServer I need of many request client/server, for example with I grid I need of call UpdateFromServer for all rows every second. I think this system is not very smart (if you have large tables with many rows).
With my system I call update function (and request all grid by server) only (and ONLY) if another client have change the a table.

1. the client edit a row of a table.
2. the OnUpdateEvent is call on server, so the server know which table is change.
3. the server send a TCP/IP message to all client with the name of edit table.
4. all the clients request from server all the table and put all the rows on a grid.

When is not OnUpdateEvent call?

Offline

#8 2011-03-27 13:05:26

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

Step 3 is not possible in HTTP, by definition of the protocol: a server can't anything broadcast to clients.

Your problem is that you handle each row as a TSQLRecord.
If you handle the whole grid content as a TSQLTableJSON, refresh will be made once for all rows.
And you can use our own grid component.

What is missing is the cell edition.
I'll probably add this feature soon.

Offline

#9 2011-03-27 13:42:02

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

Re: OnUpdateEvent and client

Yes I know, for this reason I use Indy components for point 3, I need only a "working" OnUpdateEvent and if possible know the ip address of client (but this is not possible)...
I cannot use the grid component because on my project I use NextGrid (of BergSoft) component for grid and not defualt delphi grid.

Offline

#10 2011-03-27 13:48:33

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

You can use TSQLTableJSON with whatever grid component you want.

This TSQLTableJSON could be used to be refreshed in just one call.

Offline

#11 2011-04-20 16:35:47

array81
Member
From: Italy
Registered: 2010-07-23
Posts: 411

Re: OnUpdateEvent and client

The OnUpdateEvent event is call before or after data write in the database?

From my test the event is call before change the data inside the database. So if I use it to update my GUI I cannot found the data.

I think this event should be call after data write, in alternative you should add a new event.

Last edited by array81 (2011-04-20 16:57:32)

Offline

#12 2011-04-20 18:25:35

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

OnUpdateEvent is meant to be SERVER-side, that is to check for user rights e.g. BEFORE performing any operation.
It was not designed at all to handle GUI trigering, because it will break the stateless and n-tier approach of the framework.

In short: it's not needed nor a good idea to use such a "GUI mediator pattern".

Offline

#13 2011-04-22 07:55:51

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,270
Website

Re: OnUpdateEvent and client

array81 wrote:

The OnUpdateEvent event is call before or after data write in the database?

I just checked the code, and update the documentation:
OnUpdateEvent is called BEFORE deletion, and AFTER insertion or update.

Offline

Board footer

Powered by FluxBB