28.08.2013, Vladimír Klaus, navštíveno 8879x

Delphi

Společným jmenovatelem všech těchto chybových hlášení je to, že jsou značně zavádějící a vůbec neukazují na pravou příčinu chyby. Ostatně proto vznikl tento vysvětlující článek.

Operace s více kroky vedla k vytvoření chyb. Zkontrolujte všechny stavové hodnoty.

Původní znění: Multiple-step operation generated errors. Check each status value error

Podivné hlášky v Delphi

Tato chyba znamená, že jedno nebo více polí, které vkládáte/aktualizujete obsahuje neplatnou hodnotu. Důvodů může být více:

  1. Řetězcová hodnota je vložena do číselného pole.
  2. Nějaké neplatné datum je vloženo do pole datum.
  3. Řetězcová hodnota je delší, než je velikost pole řetězce.
  4. Hodnota NULL je vložena do pole, které hodnoty NULL nepovoluje
  5. Hledáte hodnotu, která je delší než pole, ve kterém hledáte, tedy např. TableTemp.Locate('Stav', Hodnota, []) způsobí chybu, pokud pole Stav bude délky 20 a Hodnota bude mít více než 20 znaků.
  6. V SQL Serveru jsem měl pole "time(0)", což ADO nepodporuje, takže se do Delphi TADOTable nepřeneslo (ano, vůbec se dané pole nenačte, Delphi nehlásí v Design modu žádnou chybu, ale až později v runtimu může dojít k této chybě) a protože na něm bylo závislé kalkulované pole, způsobilo to při otevření tabulky opět tuto chybu.

Velmi nepříjmené je to, že se většinou nedozvíte, která hodnota/pole dělá problém. Důvodem je to, že k této chybě dojde až při ukládání celého záznamu (Table.Post), nikoliv při přiřazování hodnoty (TableNazev.Value:='abc').

Řádek nelze nalézt a aktualizovat. Pravděpodobně byly od posledního čtení změněny některé hodnoty.

Původní znění: Row cannot be located for updating. Some values may have changed since it was last read.

Podivné hlášky v Delphi

K této chybě dochází, když se založí záznam (v databázovém gridu třeba pomocí tlačítka INS), vyplní se některé hodnoty, přejde se na jiný záznam a pak se klikne na zaškrtávátko (odpovídá nějakému boolean poli) u toho před chvílí vytvořeného záznamu. Ve chvíli, kdy opět odcházíte na jiný záznam, zobrazí se tato chyba.

Podobně se chyba může objevit, pokud při zakládání záznamu nevyplníte položku s částkou. Když se pak k záznamu vrátíte, částku vyplníte, tak při uložení opět dochází k této chybě.

Řešením je například vyplnění boolean, integer, currency apod. hodnot hned při založení záznamu:

procedure TMainDataModule.TableUlohyAfterInsert(DataSet: TDataSet);
begin
  TableUlohyPovoleno.Value:=true;
  TableUlohyRocniPojistne.Value:=0;
  TableUlohyFrekvencePlateb.Value:=1;
end;

Druhým důvodem bývá vlastně přesně to, co uvádí hláška. Tedy že v nějakém okamžiku (1) načtete údaje z tabulky třeba do mřížky nebo jen otevřete tabulku (TTable). Později (2) někdo nějak tyto hodnoty upraví - např. změní jméno. Vy ovšem v tabulce/mřížce vidíte stále to původní jméno. A to se nakonec (3) rozhodnete změnit a záznam uložit. Jenomže měníte něco, co už bylo změněno a dochází ke konfliktu. A dochází k němu proto, že je aplikováno optimistické zamykání (předpokládá se, že se nebude jeden záznam upravovat vícekrát), tedy že vlastně záznam při editaci není zamčen. Kdyby bylo aplikováno pesimistické zamykání , nemohla by situace (2) vůbec nastat, protože by už v ten okamžik záznam nešel změnit.

Třetím důvodem může být dotaz používající JOIN. Vy výsledku dotazu pak může chybět klíč (např. ID), protože místo něj bude "Klienti.ID". Dotaz sám o sobě bude samozřejmě vykonán bez problému, ale pak nemusí projít třeba Query.Delete, protože se nebude moci odkázat na ID a bude si myslet, že takový řádek neexistuje. Řešením je přepsat dotaz tak, aby takové pole bylo vždy k dispozici pod svým správným názvem. Tedy například ze SELECTu odstranit stejně se jmenující sloupce těch dvou tabulek apod. nebo si pomoci dalším dotazem, jako je v tomto příkladu.

SELECT * FROM Klienti WHERE ID IN (
  SELECT Klienti.ID FROM Klienti
  LEFT JOIN Smlouvy 
  ON Klienti.ID=Smlouvy.IdKlienta 
  WHERE Smlouvy.ID IS NULL 
) 

Jiným řešením je pak unikátní pojmenování i ID polí, tedy třeba IdKlienta a IdSmlouvy.

Operace musí používat aktualizovatelný dotaz.

Původní znění: Operation must use an updateable query

Podivné hlášky v Delphi

K chybě dochází při pokusu o zápis do MS Access databáze (*.mdb). Je třeba nastavit práva k zápisu/změně do tohoto databázového souboru. To se dělá pomocí kontextového menu Vlastnosti > Zabezpečení.

Podivné hlášky v Delphi

Je ale také možné, že databáze má práva v pořádku, ale složka, ve které je uložena, potřebná práva nemá. A to buď z principu – soubor instaloval administrátor do nějaké chráněné složky a pracuje s ní obyčejný uživatel, který práva nemá a mít nemůže, nebo někdo práva na složku ručně upravil.

Pokud je databáze instalována, informujte autora instalace, aby zajistil, že je databáze instalována do správné složky a má nastavená potřebná práva, což může být v případě InnoSetupu např. „Permissions: everyone-modify“.

K MS Access databázi se dá přistupovat třeba přes ASP.NET a i v tomto případě jde o nastavení potřebných práv. Více v článku:

http://www.mikesdotnetting.com/Article/74/Solving-the-Operation-Must-Use-An-Updateable-Query-error