You are not logged in.
Pages: 1
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
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
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
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
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
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
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
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
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
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
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
Pages: 1