Запросить документ на основе ссылки на кэшированный объект - PullRequest
5 голосов
/ 11 июля 2019

У меня есть два типа объектов User и Company, данные которых хранятся в коллекциях MongoDB user и company. User содержит ссылку на Company. Я могу запросить пользователя, используя следующий код в UserRepository:

$this
  ->createQueryBuilder()
  ->field('employer')->references($company);

Company однако это тяжелый используемый объект, который кэшируется с помощью Redis. Когда кеша нет, все работает нормально. Но когда экземпляр компании был извлечен из кэша. Единица работы Доктрина не знает об этом случае. Поэтому выполнение приведенного выше кода приведет к следующей ошибке:

Cannot create a DBRef for class App\Document\Company without an identifier. Have you forgotten to persist/merge the document first?

Я обнаружил, что могу использовать хак, чтобы зарегистрировать компанию с единицей работы после получения ее из Redis:

$company = $this->fetchFromCache($params);
$documentManager->getUnitOfWork()->registerManaged($company, $company->getId(), []);

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

1 Ответ

0 голосов
/ 21 июля 2019

К сожалению, если вы хотите использовать ODM для запросов, вам нужно как-то сообщить ODM о вашем объекте. Хотя ваш registerManaged будет работать при регистрации документа в UnitOfWork, у него есть недостаток, что любые ваши отношения могут быть разорваны и / или Doctrine будет считать их новыми во время сохранения / сброса. Вы можете попробовать что-то подобное:

$company = $this->fetchFromCache($params);
if ($dm->getUnitOfWork()->containsId($company->getId(), Company::class)) {
    return $dm->find(Company::class, $company->getId());
}
return $dm->merge($company);

Как отмечалось ранее, merge будет рекурсивно объединять ваши документы и встроенные в них документы / отношения и помечать их как управляемые ODM, точно так же, как они будут только получены. Обратите внимание, что слияние будет соответствовать вашим каскадным настройкам для справок. Более подробную информацию о слиянии можно найти в документации . Также помните, что объединяемые документы могут влиять на уже извлеченные документы и обновлять их поля тем, что объединяется.

Merge операция будет выполнена только один раз, как раз перед тем, как мы проверяем, управляет ли ODM компанией, идентифицированной по идентификатору, выбранному из кэша. Если это произойдет, мы вызываем $dm->find(), который не попадет в базу данных, так как сначала он найдет карту объектов в памяти и вернет вам уже управляемый экземпляр. Таким образом, вы всегда получите документ, управляемый ODM, избегая запроса к базе данных.

...