基于对缓存对象的引用来查询文档

时间:2019-07-11 15:34:01

标签: php doctrine doctrine-odm

我有两种类型的对象UserCompany,其数据存储在MongoDB集合usercompany中。 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 :(得分:0)

不幸的是,如果您想使用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管理,就像它们将被提取一样。请注意,合并将符合您的cascading settings供参考。有关合并的更多信息,请参见in the docs。另外请注意,合并文档可能会影响已获取的文档并使用正在合并的内容更新其字段。

Merge操作将只执行一次,就像在检查ODM是否已经管理从缓存中获取的ID所标识的公司之前一样。如果是的话,我们正在调用$dm->find(),它将不会打到数据库,因为它首先会在对象的内存映射中查找并返回已被管理的实例。这样,您将始终获得由ODM管理的文档,而无需查询数据库。