Nette Database Cache problém – Cannot read an undeclared column
- Blaueminence
- Člen | 31
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.
- Blaueminence
- Člen | 31
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í.
- Blaueminence
- Člen | 31
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
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
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
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
- kolsi
- Člen | 131
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
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í?