Отключение, кеширование и слияние доктрины

Я нахожусь в Доктрине 2.3. У меня есть следующий запрос:

$em->createQuery(' SELECT u, c, p FROM Entities\User u LEFT JOIN u.company c LEFT JOIN u.privilege p WHERE u.id = :id ')->setParameter('id', $identity) 

Затем я беру это, получаю результат (который представляет собой массив, я просто беру первый элемент) и запускаю detach $em->detach($result); ,

Когда я выхожу из кэша (используя драйвер кэша APC от Doctrine), я делаю:

 $cacheDriver = new \Doctrine\Common\Cache\ApcCache(); if($cacheDriver->contains($cacheId)) { $entity = $cacheDriver->fetch($cacheId); $em->merge($entity); return $entity; } 

Я надеюсь, что это позволит повторно включить загрузку отношений в объект, поскольку существует много других отношений, связанных с объектом User, отличным от того, что показано в этом запросе.

Я пытаюсь создать новый объект вроде этого:

 $newEntity = new Entities\ClientType(); $newEntity['param'] = $data; $newEntitiy['company'] = $this->user['company']; $em->persist($newEntity); $em->flush(); 

Когда я это сделаю, я получаю сообщение об ошибке:

 A new entity was found through the relationship 'Entities\ClientType#company' that was not configured to cascade persist operations for entity: Entities\Company@000000005d7b49b500000000dd7ad743. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Entities\Company#__toString()' to get a clue. 

Это отлично работает, когда я не использую объект компании под пользовательским объектом, который я получил из кеша. Есть ли способ сделать эту работу, поэтому мне не нужно возвращать объект компании из базы данных каждый раз, когда я хочу использовать ее в отношениях с новым объектом?

Изменить: это то, что у меня есть в моей пользовательской сущности, связанной с этими двумя отношениями:

 /** * @ManyToOne(targetEntity="Company" , inversedBy="user", cascade={"detach", "merge"}) */ protected $company; /** * @ManyToOne(targetEntity="Privilege" , inversedBy="user", cascade={"detach", "merge"}) */ protected $privilege; 

Я все еще получаю ту же ошибку.

Второе редактирование: попытка использования $em->contains($this->user); и $em->contains($this->user['company']); оба возвращают false. Что звучит … неправильно.

При объединении пользователя вы хотите, чтобы связанная с ним компания и Привилегия были объединены, правильно?

Этот процесс называется каскадным:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations

В свой пользовательский объект поместите cascade={"merge"} в аннотацию @ManyToOne (или другой тип определения определения, который вы используете) для $company и $privilege .

И если вы хотите, чтобы вызов отсоединения также был каскадным (что рекомендуется), введите cascade={"detach", "merge"} .

ps: Не ставьте такие каскады с обеих сторон одной ассоциации, вы создадите бесконечный цикл;)

Редактировать:

Этот фрагмент кода:

 $entity = $cacheDriver->fetch($cacheId); $em->merge($entity); // <- return $entity; 

должно быть:

 $entity = $cacheDriver->fetch($cacheId); $entity = $em->merge($entity); // <- return $entity; 

Дело с merge() заключается в том, что он оставляет объект, который вы передаете, в качестве аргумента нетронутым, и возвращает новый объект, представляющий управляемую версию объекта. Поэтому вы хотите использовать возвращаемое значение, а не аргумент, который вы передали.