Cache – zmizí data a netuším proč

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

Ahoj všem.

Nevím si radu s tímto. Vypisuji pracovní místa, která při prvním načtení vytáhnu z databáze pomocí Doctriny.

	$qb->select('j')
		->from('\App\Entities\Job', 'j')
		->leftJoin('j.regions', 'r')
		->leftJoin('j.company', 'c')
		->groupBy('j.uid')
		->orderBy('j.updated', 'DESC')
		->setFirstResult($paginator->offset)
		->setMaxResults($paginator->itemsPerPage);
// nějaké další podmínky .....
		$qb->andWhere("(r = :region)");
					$qb->setParameter("region", $region);

	$jobs = $qb->getQuery()->getResult();

pak je uložím do cache

	$cache->save($cacheSlug, $jobs
, array(\Nette\Caching\Cache::TAGS => array($region->getSlug() . "jobs")));

Zatím vše funguje podle předpokladu.

Dál potřebuji, aby si uživatel mohl přidávat k jednotlivých pracovním místům „záložky“. Mám tedy entitu Bookmark, která odkazuje na entitu User a entitu Job.

Když vytvoří nějakou záložku pro uživatele a prac. pozici, vše funguje.

Když potom smažu cache, tak první načtení z DB se zobrazí v pořádku. Jenže při druhém načtení, které je už z cache, chybí u inzerátů, které jsou označené záložkou, vazby na další entity.

Konkrétní příklad:

  1. Dělník, Ronal ČR
  2. Prodavač, Jednota a.s.
  3. Uklízečka, Agrozet

Tímto stylem mi to vypisuje a název společnosti dostávám přes

	$job->getCompany()->getName();

Jenže jak jsem psal, u inzerátů které označím záložkou, dostávám při volání getCompany() jen NULL

Zkouším hledat chybu už po několikáté a pořád marně.

Tuší někdo, v čem by mohla být příčina?

DÍKY MOC

Martin Kejzlar

Editoval kejlicz (26. 10. 2016 16:30)

David Matějka
Moderator | 6445
+
+1
-

Ukladat do cache entity neni nikdy dobry napad.

  1. bud ukladej nejaky transformovany data, ktera potrebujes nekde vypsat
  2. nebo se na cachovani vykasli. nebo ho opravdu potrebujes?
kejlicz
Člen | 201
+
0
-

Cachování dle mého názoru potřebuju. Jedná se o dost navštěvovaný web a na době načtení dost záleží. Co jsem testoval, tak s použití cache je to tak 3x-5× rychlejší. Bez použití cache by se to často ani nestíhalo pod tlakem požadavků generovat.

S cache se učím a říkal jsem si, že s entitami může být problém. Ale zkusil jsem, běhalo to a tohle je první věc, které mi zlobí. Teda jestli je to vůbec tím a není tam nějaká jiná chyba.

Jaký máte názor na to, že bych k entitě Job přidal textové položky companyName a companyNameSlug, jen pro ošetření této situace? netahal bych to tedy z navázaných entit, ale přímo z této. Prakticky bych to mohl použít i v jiných částech aplikace a bylo by to rychlejší.

David Matějka napsal(a):

Ukladat do cache entity neni nikdy dobry napad.

  1. bud ukladej nejaky transformovany data, ktera potrebujes nekde vypsat
  2. nebo se na cachovani vykasli. nebo ho opravdu potrebujes?
Jan Mikeš
Člen | 771
+
0
-

Pokud potřebuješ cachovat, doporučuji si vytvořit DTO, které bude z entity vycházet a ten pak cachovat, za entitami je mnoho magie a cachování jim určitě neprospěje :-).

kejlicz
Člen | 201
+
0
-

Díky oběma. Zkusím tedy to DTO, abych necachoval přímo entitu.

David Matějka
Moderator | 6445
+
0
-

@kejlicz jestli je problem s dotazem, tak zkousel si prvne optimalizovat sql? jinak ukladat companyName neni dobry napad, udelej radeji to, co rika @JanMikeš , pokud se opravdu bez cachovani neobejdes.

Michal Hlávka
Člen | 190
+
0
-

Entity necachuj, cachuj az data co jsou poslany v odpovedi serveru. Tudiz ty co vidi uzivatel. Cache pak muzes invalidovat novym pracovnim mistem, nebo mu nastavit expiraci. Samozrejme se muze stat to, ze ze s novym pracovnim mistem, se to zase jebne a bude se to nacitat a server ti muze spatnout. To uz je pak dobry si procist nejake clanky co se cachovanim zabivaji a jak tohle resi.

Muzu te odkazat na videa z NetteFw srazu (?) nevim jestli se to tak jmenuje, kde jeden celej den bylo venovano prednaskam o cachovani. Tam by si urcite mohl nabrat dobrou inspiraci, protoze tam jsou priklady z praxe a ukazky kodu.

Jan Mikeš
Člen | 771
+
0
-

Ještě abych vysvětlil, proč dostáváš NULL při $job->getCompany()->getName();
V tom tvém query builderu selectuješ explicitně totiž pouze data z entity Job. To by až tak nevadilo, pokud by jsi výsledek necachoval, protože aplikace dokáže v průběhu poslat další query do databáze a data si dodatečně vytáhnout. Problém nastane až když entitu serializuješ a uložíš ji do cache – tam se uloží v tom stavu v jakém aktuálně je, tedy s chybějícími daty.

Pokud chceš tady problém vyřešit rychleji, vyselectuj si všechna data napříč všemi vazbami s entitou, se kterými kdekoliv v aplikaci pracuješ (pomocí ->addSelect() v query builderu), a až potom tu entitu cachuj, ale nedoporučuji to, protože za entitami je opravdu dost magie.

Pokud chceš jít tou správnější cestou, použij DTO (těch DTO můžeš mít klidně 20 pro jednu entitu, vždy podle use-case, to ti ale zase může narůstat velikost cache).

Editoval Jan Mikeš (26. 10. 2016 17:18)

pitr82
Člen | 121
+
0
-

Zdravím, můžete ukázat příklad kešování s použitím DTO ?