28.08.2013, Vladimír Klaus, navštíveno 8879x
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
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:
- Řetězcová hodnota je vložena do číselného pole.
- Nějaké neplatné datum je vloženo do pole datum.
- Řetězcová hodnota je delší, než je velikost pole řetězce.
- Hodnota NULL je vložena do pole, které hodnoty NULL nepovoluje
- 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ů.
- 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.
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
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í.
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