Hi,
I agree that you can't from components level unprepare and then prepare all datasets. But I think I can do it manually in my application according to my needs. I made some changes in ODAC to prepare this mechanism. The only thing which I need are two events which are fired while reconnect process. The first one is event called OnBeforeReconnect. It is intended to inform application that reconnect proces was started. Event type declarations looks like:
Code: Select all
TBeforeReconnectEvent = procedure (Sender: TObject; const AReconnectAttempt: Integer;
const AErrorComponent: TObject) of object;
this event is declared in TCustomDAConnection class and published in TOraSession. Event is fired from DoError procedure:
Code: Select all
procedure TCustomDAConnection.DoError(E: Exception; var Fail, Reconnect, Reexecute: boolean;
ReconnectAttempt: integer; var ConnLostCause: TConnLostCause);
var
i: integer;
FatalError: boolean;
RetryMode: TRetryMode;
begin
ConnLostCause := clUnknown;
TDASQLMonitorClass(SQLMonitorClass).DBError(EDAError(E));
FatalError := EDAError(E).IsFatalError;
if FatalError then begin
with EDAError(E) do begin
ConnLostCause := DetectConnLostCause(Component);
Reconnect :=
(Connected
or ((ReconnectAttempt > 0) and Options.LocalFailover) // After first abortive attempt Connected = False
or (ConnLostCause = clConnect) and Options.DisconnectedMode) // For disconnect mode TODO:
and (IsFailOverAllowed or (ConnLostCause = clConnectionApply));
if Reconnect then
begin
// Wywołanie zdarzenia umożliwiającego preparację zbiorów danych przed wykonaniem ponownego połączenia.
if Assigned(FOnBeforeReconnect) then
FOnBeforeReconnect(Self, ReconnectAttempt, Component);
...
The second event was named OnAfterRestoreFailOver and is also declared in TCustomDAConnection class. This event is fired from RestoreAfterFailOver procedure. After changes procedure looks like:
Code: Select all
procedure TCustomDAConnection.RestoreAfterFailOver;
var
i: integer;
begin
for i := 0 to FTransactions.Count - 1 do
FTransactions[i].Restore;
if Assigned(FOnAfterRestoreFailOver) then
FOnAfterRestoreFailOver(Self);
end;
This are whole changes in ODAC components. Now what I should to do in application:
1. In OnBeforeReconnect event at first I'm marking all prepared datasets as unprepared using code:
Code: Select all
if TCustomDADataSetFriend(lDataSet).Data.Prepared then
TCustomDADataSetFriend(lDataSet).Data.Prepared := False;
Its it required to run reconnect proces in ODAC components. I must to mark dataset as unprepared. Calling regular Unprepare method will cause memory leak problems. I know it is not elegant solution, but I had no choice.
In this event I'm also collecting whole prepared dataset in the list which is used in second event.
2. In OnAfterRestoreFailover I'm preparing back again whole datasets which was marked as unprepared in OnBeforeReconnect event. I'm doing this task using code:
Code: Select all
TCustomDADataSetFriend(lItem.Component).Data.Prepared := True;
TCustomDADataSet(lItem.Component).UnPrepare;
TCustomDADataSet(lItem.Component).Prepare;
But this is my scenario. I think it could be done in different way. Datasets could be prepared again just before reopening or some other simillar solutions could be used.
The only condition is: components should allow to do this actions.
What do you think about described method?