"Database refetch failed; row with signature ‚601‘ does not exist!

Pepiik
Člen | 10
+
0
-

Ahoj,
Na serveru se mi náhodně objevují chyby „Database refetch failed; row with signature ‚xxx‘ does not exist!“ Půl dne laboruji kdy přesně to uděla a zjistil jsem konkrétní postup kdy to vždy udělá.

Nette/Database 3.1.6 (dělalo to i na starších verzích)

  1. Vymaže se cache
  2. První request na server: Dotaz nad tabulkou activities nevrátí žádný výsledek
  3. Druhý request na server: Dotaz nad tabulkou activities vrátí nějaký výsledek, vleze to do foreache a nad zavoláním metody toArray() to hodí chybu.
  4. Pak už to chybu nikdy nehodí dokud se zase nesmaže cache.
$today = date('Y-m-d', time());

$late_activities = $this->database->table('activities')
    ->where('due_date < ?', $today)
    ->where('id_activity_state ?', 1)
    ->fetchAll();

foreach ($late_activities as $activity) {

    $activity->update([ 'id_activity_state' => 3]);

    $xx = $activity->toArray(); // Tady spadne s hláškou "Database refetch failed; row with signature '601' does not exist! "

}

Zkoumal jsem co se změní v cache a ve druhém requestu (kdy to hodí tu chybu) se změní obsah u jednoho souboru.
z 000068a:2:{s:4:"time";s:21:"0.01619100 1671490756";s:10:"serialized";b:1;}a:1:{s:11:"id_activity";b:1;}
na 000068a:2:{s:4:"time";s:21:"0.66501100 1671490852";s:10:"serialized";b:1;}b:0;

Je to bug nebo vlastnost a mám to udělat jinak?

Díky

nightfish
Člen | 472
+
0
-

@Pepiik Počti si v těchto odkazech, třeba narazíš na něco nápomocného.

https://forum.nette.org/…es-not-exist
https://github.com/…e/issues/187

Pavel Kravčík
Člen | 1180
+
+2
-

Stávalo se ve staré verzi, pak to David opravil. Možné rady:

  1. Upgrade Nette
  2. Explicitně vyjmenovat všechny sloupce v select (to nám pomohlo v jednom projektu)
  3. Zavolat dotaz znovu (pomohlo v jiném projektu), místo $activity->toArray() → $newSql->fetch()
Kamil Valenta
Člen | 758
+
+1
-

Ano, často pomůže select s vyjmenovanými sloupci.
Ty si nejprve selectneš věty, které mají id_activity_state=1,
pak jim uděláš update na id_activity_state=3.
Pak třeba v nějakém ifu sáhneš na sloupec, který v původním selectu nebyl zahrnut, tak se provede refetch, ale ten záznam při where id_activity_state=1 už neexistuje, protože nyní má id_activity_state=3.

Pepiik
Člen | 10
+
0
-

Díky za odpovědi.

Chtěl jsem spíš více pochopit jak to funguje. Přidal jsem tam teda navíc ještě ->select('*') a už to nedělá.

@KamilValenta
Chápu co myslíš, ale tím nexistujícím řádkem po update to není. Protože po změně té cache co jsem vypsal to funguje. Asi si to nějak špatně při tom prvním requestu nacachuje strukturu viz ten rozdíl co jsem posílal. Jakoby to nedokázalo rozeznat primarní klíč. Jak jsem tam přidal navíc ten ->select('*'), tak už se cache vygeneruje rovnou tím druhým způsobem. Jinej kód tam není, testoval jsem to přesně na takto jak jsem to poslal.

Je to takovej neuspokojivej fix, ale už se v tom dál babrat nebudu :D

Řešení:

$late_activities = $this->database->table('activities')
	->select('*')
    ->where('due_date < ?', $today)
    ->where('id_activity_state ?', 1)
    ->fetchAll();
mystik
Člen | 289
+
0
-

@Pepiik Nette database je totiz chytra a pokud pri provadeni zjisti ze musela polozit druhy dotaz aby donacetla sloupce co napoprve chybely, tak si to zapamatuje a priste uz poklada jen jeden dotaz rovnou se vsemi pouzitymi sloupci takze ten druhy neni nutny.

Kamil Valenta
Člen | 758
+
0
-

Pepiik napsal(a):

Chápu co myslíš, ale tím nexistujícím řádkem po update to není.

Dobře, jak myslíš.
Už jen tak mimo hru si můžeš zkusit přečíst tu exceptionu, kterou to vykoplo a zamyslet se nad tím, z jakého důvodu ten row už „neexistuje“.

A že řešení přineslo select(‚*‘), ale zrovna tak by stačilo udělat ten update až na konci (ovšem v tom poli by se ta hodnota na 3 musela změnit jinak).