Nette Database Cache problém – Cannot read an undeclared column

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Blaueminence
Člen | 31
+
0
-

Dobrý den,

mám problém s cache u databáze. Na dvou místech v aplikaci mi to vytrvale hlásí

Nette\MemberAccessException
Cannot read an undeclared column 'label_en'.

apod.

Když smažu Cache (stačí jen ručně smazat složku _Nette.Database.xxxx), problém se na chvíli napraví, ale po delší době (orientačně v řádu několika hodin) to chybu začne hlásit znovu.

Konkrétně je to na místě dvoujazyčného dropdown menu, které cachuji v šabloně

{cache [$mobile,$ie,$admin,$page_id,$lang], expire => '+20 days', tags=>["nastaveni"]}
...
{var $labelVarName="label_".$lang}
{$item->$labelVarName}
...
{/cache}

a navíc to chybu vždy hlásí až na druhé úrovni menu; identický kód o pár řádků výše žádnou chybu nehlásí. Také se to stává výhradně u anglické verze ($lang="en"), u české (cz) se to nikdy nestalo.

Dále se mi to děje v administrační sekci webu, konkrétně

<a n:href="Lide:edit $clovek->id_clovek" title="Upravit člověka" class="{if $prihlaska->retence==1}retence{/if}">
      {$clovek->jmeno} {$clovek->prijmeni}
</a>

kde hlásí Cannot read an undeclared column ‚retence‘. Jinde v aplikaci používám identickou konstrukci, a tam chyby nikdy nehází.

Upgradoval jsem Nette na 2.2.7, ale ani to nepomohlo. Díky za případnou pomoc.

tomasn
Člen | 8
+
0
-

Mě to dělá naprosto to samé. Náhodně u nějakých sloupců. Najednou to začne hlásit že není deklarovaný samo od sebe. Musel jsem dát do cronu mazání cache co hodinu, než to zkusím celé posunout na Nette 2.3.

Blaueminence
Člen | 31
+
0
-

Evidentně jde o nějaký bug přímo v Nette, protože na všechno ostatní mi tady přímo tvůrci do pár hodin vždycky odpověděli.. tak snad s tím něco udělají.

Caine
Člen | 216
+
+1
-

Starej znamej a neopravitelnej bug, vleknouci se od 2.0.. Staci u NDB nastavit cache na memory nebo devnull a nebo explicitne uvadet sloupce, ktere se maji vybirat v SELECTu (napr table.*)

Blaueminence
Člen | 31
+
0
-

Zkusil jsem to, zatím to zdá se funguje.

Blaueminence
Člen | 31
+
0
-

Už to zas nefunguje. Jak přesně vypadá ten explicitní výběr sloupce? Zkusil jsem

$menu = $database->table('menu')->select('id_menu_item, ident, label_cz, label_en, icon, anchor, id_parent, admin, link, obsah_cz, obsah_en, hidden')->where('hidden = 0')

ale nepomohlo ti, pořád to hází to

Nette\MemberAccessException
Cannot read an undeclared column 'label_en'.

při procházení, jak píšu na začátku.

jpatus
Člen | 5
+
0
-

Máme veľmi podobný problém.

Dotaz v rámci jednej tabuľky funguje v poriadku, pokiaľ sa však odkážeme na tabuľku inú (je jedno či je v selecte spomenutá explicitne alebo nie), pre niektoré položky jednoducho nenájde príslušný záznam.

Pseudokód:
$return = $this->connection->table(...)->where(...)->order(...)->select('*, user.*');
foreach ($return as $r) {
\Tracy\Debugger::barDump($r->user->name . $r->user->surname);
}

Pri vypnutej cache sa do laděnky vypíšu správne záznamy, pri zapnutej cache v niektorých prípadoch dostaneme „Notice: Trying to get property of non-object“.

Vo verziách 2.1.x a 2.2.x stačilo zmazať cache, prekrížiť prsty a dúfať. Ak to nepomohlo, zmazať cache znova. Typicky sa problém vyskytoval častejšie, ak pri mazaní cache niekto pristúpil k webu.

Vo verzii aktuálnej toto už ale nestačí a jediným východiskom v našom prípade bolo dočasne cache vypnúť úplne.

Problém má tendenciu vyskytovať sa iba nad niektorými tabuľkami s veľkým počtom položiek (stotisíce), netýka sa všetkých, hlavne nie menej rozsiahlych tabuliek.

Editoval jpatus (22. 4. 2015 16:58)

jpatus
Člen | 5
+
0
-

Zdá sa, že riešenie by mohlo byť na:
https://github.com/…se/issues/15#…

Po tejto úprave sa problém zatiaľ neprejavil.

oskarmaniak
Člen | 29
+
0
-

Tento problém mám také stále. Ve verzi 2.2. mi to nefungovalo ani, když jsem vypnul Cache, což ve 2.3.2 už aspoň očividně zatím funguje. Ale vypnutou Cache je mít určitě škoda.

Pokoušel jsem se i o tu úpravu z předešlého příspěvku, ale chyba je stále.

Jakmile přímo v latte šabloně zavolám foreign key

$item->device->name

tak dostanu Trying to get property of non-object.

Řešení je tedy výše zmiňované

cacheStorage:
        class: Nette\Caching\Storages\DevNullStorage

nebo

cacheStorage:
        class: Nette\Caching\Storages\MemoryStorage

ale předpokládám, že ani to MemoryStorage, není to pravé? Jak tedy správně rozchodit FileStorage?
Je opravdu stále trvající bug v Nette, nebo je potřeba změnit způsob vypisování foreign key hodnot z databáze?

Dík

medhi
Generous Backer | 255
+
0
-

Mám stejný problém ve verzi 2.3.3

kolsi
Člen | 131
+
0
-

Ahoj, také jsem si všimnul jedné anomálie, která bude mít nejspíš něco společného s cache. Stává se to prakticky nahodile, většinu času spíš vůbec, ale přesto občas :)

Při tomto pseudokódu se mi to podařilo reprodukovat, ale stává se to i při komplikovanějších situacích:

$rows = $this->context->repository->findAll();
foreach($rows as $row) {
   // přečti nějaký sloupec z DB...
   // => provede se "SELECT sloupec1 FROM..."
   // => v $rows se naplní data objekty typu ActiveRow, které obsahují hodnotu pro "sloupec1"
   $x = $row->sloupec1;
   ...
}

...

foreach($rows as $row) {
   // přečti jiný sloupec z DB
   // provede se "SELECT * FROM..."
   // v $rows se všechna data přepíšou novými objekty typu ActiveRow (nyní už obsahují hodnoty všech sloupců)
   // $row pro tuto iteraci však stále obsahuje starý ActiveRow a další iterace už obsahují nové ActiveRow
   $y = $row->sloupec2;
   ...
}

Jde hlavně o ten druhý cyklus, kde přestože pracují stále se stejným Selection, tak všechny ActiveRow jsou přepsány novými objekty – neměly by se pouze aktualizovat již existující instance dotaženými daty? A v první iteraci proměnná $row bude obsahovat stále starý objekt.

V tomto jednoduchém pseudokódu to nebude představovat žádný problém, ale už se nám vyskytla komplikovanější situace, kde to vadilo.

kolsi
Člen | 131
+
0
-

Mám k tomuto ještě dotaz. Mohl by někdo znalý vysvětlit, zda by nebylo lepší něco v tomto smyslu

Database\Table\Selection.php, aktuální stav:

protected function execute()
{
   ...
	$this->rows = array();
	$usedPrimary = TRUE;
	foreach ($result->getPdoStatement() as $key => $row) {
		$row = $this->createRow($result->normalizeRow($row));
		$primary = $row->getSignature(FALSE);
		$usedPrimary = $usedPrimary && $primary;
		$this->rows[$primary ?: $key] = $row;
	}
	$this->data = $this->rows;
   ...
}

Navrhovaný pseudokód:

...
foreach ($result->getPdoStatement() as $key => $row) {
    $normalizedRow = $result->normalizeRow($row);
	$primary = $row->getSignature(FALSE);
	$usedPrimary = $usedPrimary && $primary;

	$currentRow = &$this->data[$primary ?: $key];
	if(isset($currentRow)) {
		$currentRow->updateRow($normalizedRow);
	} else {
		$row = $this->createRow($normalizedRow);
		$currentRow = $row;
	}
}
...

Nebo je v tom ještě nějaký háček, proč se musí znovu vytvářet celý ActiveRow a nestačí aktualizovat ten stávající?