{"action":"created","issue":{"url":"https://api.github.com/repos/doctrine/doctrine2/issues/6096","repository_url":"https://api.github.com/repos/doctrine/doctrine2","labels_url":"https://api.github.com/repos/doctrine/doctrine2/issues/6096/labels{/name}","comments_url":"https://api.github.com/repos/doctrine/doctrine2/issues/6096/comments","events_url":"https://api.github.com/repos/doctrine/doctrine2/issues/6096/events","html_url":"https://github.com/doctrine/doctrine2/issues/6096","id":184541361,"number":6096,"title":"Second Level Cache, QueryCache, Eviction","user":{"login":"wtorsi","id":2115840,"avatar_url":"https://avatars.githubusercontent.com/u/2115840?v=3","gravatar_id":"","url":"https://api.github.com/users/wtorsi","html_url":"https://github.com/wtorsi","followers_url":"https://api.github.com/users/wtorsi/followers","following_url":"https://api.github.com/users/wtorsi/following{/other_user}","gists_url":"https://api.github.com/users/wtorsi/gists{/gist_id}","starred_url":"https://api.github.com/users/wtorsi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wtorsi/subscriptions","organizations_url":"https://api.github.com/users/wtorsi/orgs","repos_url":"https://api.github.com/users/wtorsi/repos","events_url":"https://api.github.com/users/wtorsi/events{/privacy}","received_events_url":"https://api.github.com/users/wtorsi/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2016-10-21T18:20:51Z","updated_at":"2016-10-22T11:44:36Z","closed_at":null,"body":"Eviction non builded before queryCache is not allowed, or not performed in **DefaultCache**.\r\nWhat is the reason for this limitation? \r\n\r\n```\r\n/**\r\n     * {@inheritdoc}\r\n     */\r\n    public function evictQueryRegion($regionName = null)\r\n    {\r\n        if ($regionName === null && $this->defaultQueryCache !== null) {\r\n            $this->defaultQueryCache->clear();\r\n\r\n            return;\r\n        }\r\n\r\n\r\n        if (isset($this->queryCaches[$regionName])) {\r\n            $this->queryCaches[$regionName]->clear();\r\n        }\r\n    }\r\n```\r\nAccording to that limitation, firstly I must create cache before clearing, using **_getQueryCache($region)_** from **_EntityManager::$cache_**, like below:\r\n\r\n```\r\npublic function evictQueryCache(string $region)\r\n\t{\r\n\t\t$cache = $this->em->getCache();\r\n\t\t$region = $cache->getQueryCache($region);\r\n\t\t$cache->evictQueryRegion($region);\r\n\t\t$region->clear();\r\n\t}\r\n```\r\n\r\nWhat is the reason for this limitation?\r\n \r\n"},"comment":{"url":"https://api.github.com/repos/doctrine/doctrine2/issues/comments/255523725","html_url":"https://github.com/doctrine/doctrine2/issues/6096#issuecomment-255523725","issue_url":"https://api.github.com/repos/doctrine/doctrine2/issues/6096","id":255523725,"user":{"login":"wtorsi","id":2115840,"avatar_url":"https://avatars.githubusercontent.com/u/2115840?v=3","gravatar_id":"","url":"https://api.github.com/users/wtorsi","html_url":"https://github.com/wtorsi","followers_url":"https://api.github.com/users/wtorsi/followers","following_url":"https://api.github.com/users/wtorsi/following{/other_user}","gists_url":"https://api.github.com/users/wtorsi/gists{/gist_id}","starred_url":"https://api.github.com/users/wtorsi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wtorsi/subscriptions","organizations_url":"https://api.github.com/users/wtorsi/orgs","repos_url":"https://api.github.com/users/wtorsi/repos","events_url":"https://api.github.com/users/wtorsi/events{/privacy}","received_events_url":"https://api.github.com/users/wtorsi/received_events","type":"User","site_admin":false},"created_at":"2016-10-22T11:44:36Z","updated_at":"2016-10-22T11:44:36Z","body":"Ok, I'll try do describe \r\nI got \r\n\r\n```\r\n/**\r\n * Class Category\r\n * @package CatalogBundle\\Entity\r\n *\r\n * @ORM\\Entity(repositoryClass=\"AppBundle\\Entity\\Repository\\CategoryRepository\")\r\n * @ORM\\Cache(usage=\"NONSTRICT_READ_WRITE\")\r\n */\r\nclass Category \r\n{\r\n\r\n\t/**\r\n\t * @var integer\r\n\t * @ORM\\Column(type=\"integer\")\r\n\t * @ORM\\Id\r\n\t * @ORM\\GeneratedValue\r\n\t */\r\n\tprotected $id;\r\n\t/**\r\n\t * @var Media[]\r\n\t * @ORM\\Cache(usage=\"NONSTRICT_READ_WRITE\")\r\n\t * @ORM\\OneToMany(targetEntity=\"AppBundle\\Entity\\Media\", cascade={\"remove\"}, mappedBy=\"category\")\r\n\t * @ORM\\OrderBy({\"sortOrder\" = \"ASC\"})\r\n\t */\r\n\tprivate $medias;\r\n}\r\n\r\n/**\r\n *\r\n * @ORM\\Entity(repositoryClass=\"AppBundle\\Entity\\Repository\\MediaRepository\")\r\n * @ORM\\Cache(usage=\"NONSTRICT_READ_WRITE\")\r\n *\r\n * @Wise\\Uploadable(path=\"/media\", onUpdate=\"keep\", onDelete=\"keep\")\r\n */\r\n```\r\nAnd accordingly I have\r\n```\r\nclass Media\r\n{\r\n\t/**\r\n\t * @var integer\r\n\t * @ORM\\Column(type=\"integer\")\r\n\t * @ORM\\Id\r\n\t * @ORM\\GeneratedValue\r\n\t */\r\n\tprivate $id;\r\n\t/**\r\n\t * @var Category\r\n\t * @ORM\\Cache(usage=\"NONSTRICT_READ_WRITE\")\r\n\t * @ORM\\ManyToOne(targetEntity=\"AppBundle\\Entity\\Category\", inversedBy=\"medias\")\r\n\t * @ORM\\JoinColumn(name=\"category_id\", referencedColumnName=\"id\", nullable=false, onDelete=\"CASCADE\")\r\n\t */\r\n\tprivate $category;\r\n}\r\n```\r\n\r\nIn my controller, I'm trying to get  _**Category**_  with _**Medias**_ , sorted by _sortOrder_\r\nusing this query\r\n\r\n```\r\npublic function findByTag(bool $enabled = true)\r\n\t{\r\n\t\t$qb = $this->createQueryBuilder(\"c\", \"c.id\");\r\n\t\t$qb\r\n\t\t\t->setCacheable(true)\r\n\t\t\t->setCacheRegion(CategoryCache::CACHE_QUERY_CATEGORY)\r\n\t\t\t->setLifetime(3600);\r\n\r\n\t\t$qb\r\n\t\t\t->leftJoin(\"c.medias\", \"m\")->addSelect(\"m\")\r\n\t\t\t->where($qb->expr()->eq(\"c.enabled\", \":enabled\"))\r\n\t\t\t->andWhere($qb->expr()->eq(\"c.tag\", \":tag\"))\r\n\t\t\t->setParameter(\"enabled\", $enabled)\r\n\t\t\t->setParameter(\"tag\", $tag)\r\n\t\t\t->orderBy(\"c.sortOrder\");\r\n\r\n\t\treturn $qb->getQuery()->getResult();\r\n\t}\r\n```\r\nRegions\r\n__**Media**__ is stored in __media_region__,\r\n__**Category**__ is stored in __category_region__, \r\n__**QueryBuilder Query**__ is stored in __query_cache_region__\r\n\r\nAnd now the problem. \r\nIn case if I **only** change order of  __**Media**__ entity,  I want that my order of joined entities in query also changed, but this is not working, because, I think,  __category_region__ is not changed.\r\n\r\n```\r\n/** @var $key QueryCacheKey */ \r\n$entry = $this->region->get($key); // CacheProvider returns cached sortOrder \r\n....\r\n// $key with region set by root entity Category, so it is passed\r\n if ( ! $this->validator->isValid($key, $entry)) {\r\n\t        $this->region->evict($key);\r\n            return null;\r\n}\r\n....\r\nforeach ($entry['associations'] as $name => $assoc) {\r\n    ....\r\n    foreach ($assoc['list'] as $assocIndex => $assocId) { // cached sortOrder :(\r\n        if (($assocEntry = $assocRegion->get($assocKey = new EntityCacheKey($assoc['targetEntity'], $assocId))) === null) {\r\n            ....\r\n            return null; //not called,  and everything is ok\r\n        }\r\n    }\r\n    ....\r\n}\r\n```\r\n\r\nSetting custom region for query_builder is just a solution to not clear all cache for all builders.\r\nAlso, clearing association cache for CategoryEntity (my first thought, and I hope best solution) did not help, because there is no checks for that in hydration block in DefaultQueryCache code.\r\n\r\n \r\n"}}
{"actor":{"display_login":"wtorsi"}}