Kdy mohou nastat zvláštní problémy s ADOConnection.Connected a ADOTable.Active

22. 8. 2020, Vladimír Klaus, přečteno 117x

Delphi
SQL Server

Pokud v Delphi pracujete s databázovými tabulkami, není od věci se tu a tam ujistit o tom, zda je požadovaná tabulka skutečně otevřena, aby nedošlo k chybě. Tedy něco jako:

if MyTable.Active then ...;

Na tom není opravdu nic zásadního, ovšem jen do té doby, kdy následující kód spadne v části "Lookup". A to na naprosto nesmyslnou EOleException chybu:

Operace není povolena, pokud je objekt uzavřen.
Operation is not allowed when the object is closed.

if MyTable.Active then begin
    if MyTable.Lookup('Hodnota', AValue, 'ID') ...
end;

Takže tabulka je aktivní/otevřená, ale při hledání mi to nahlásí, že je zavřená. Šílené! Další vykonání kódu pak dokonce může vést k "Stack overflow."

Vzhledem k tomu, že podobné principy používám již mnoho let a bez problémů, bylo pátrání docela zdlouhavé a nalezené články a různé návrhy nikam nevedly.

Nakonec jsem vyzkoušel použít test na ADOConnection.Connected místo ADOTable.Active a světe div se, zabralo to! 

Co jsem tedy dělal a proč nechápu, že toto zabralo? Tedy vypnu připojení (tím se má odpojit i tabulka!), změním připojení třeba k jiné databázi, připojím se a následně otevřu i tabulku. Zkrátka nic podivného.

ADOConnection.Connected:=false;
ADOConnection.ConnectionString:='...';
ADOConnection.Connected:=true;
MyTable.Open;

Zádrhel byl asi v tom, že mezi odpojením připojení ADOConnection a následným zavřením tabulky je jistá prodleva, během které se tabulka tváří jako otevřená (což možná interně i může být), ale už není připojená k databázi a jakékoliv použití, které vyžaduje dotaz do databáze, selže.

A protože moje výše uvedené hledání v tabulce bylo použito v cizí komponentě, které zřejmě volá tuto metodu velmi často nebo na základě nějakých podnětů mimo moji kontrolu (možná i paralelně), docházelo k tomuto průšvihu.

Zatím se zdá jako nejjistější toto řešení:

if ADOConnection.Active and MyTable.Active then begin
    if MyTable.Lookup('Hodnota', AValue, 'ID') ...
end;

Kdo nebo co může být na vině, když se to dříve nestávalo:

  • Novější Delphi 10.4 místo 10.3
  • Novější Microsoft OLE DB Driver for SQL Server 18.4 místo 18.3
  • Novější DevExpress komponenty
  • Případně něco dalšího, co není na první pohled zřejmé (aktualizace Windows apod.)