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

Xat*_*too 5 php doctrine doctrine-odm

我有两种类型的对象UserCompany其数据存储在MongoDB集合user和中companyUser包含对的引用Company。我可以在UserRepository中使用以下代码查询用户:

$this
  ->createQueryBuilder()
  ->field('employer')->references($company);
Run Code Online (Sandbox Code Playgroud)

Company但是,它是一个使用率很高的对象,使用Redis进行缓存。当不存在缓存时,一切正常。但是当从缓存中获取公司实例时。教义的工作单元不了解实例。因此,执行上面的代码将导致以下错误:

Cannot create a DBRef for class App\Document\Company without an identifier. Have you forgotten to persist/merge the document first?
Run Code Online (Sandbox Code Playgroud)

我发现从Redis提取公司信息后,我可以使用黑客将该公司注册到该工作部门:

$company = $this->fetchFromCache($params);
$documentManager->getUnitOfWork()->registerManaged($company, $company->getId(), []);
Run Code Online (Sandbox Code Playgroud)

但是,这看起来很丑。有没有一种方法可以查询用户而不必让Doctrine知道Company对象或更改我的数据模型?

mal*_*rzm 1

不幸的是,如果您想使用 ODM 进行查询,您需要以某种方式让 ODM 了解您的对象。虽然您的意志registerManaged在工作单元中注册文档时会工作,但它有一个缺点,即您可能拥有的任何关系都将被破坏和/或 Doctrine 会假设它们在持久/刷新期间是新的。你可以尝试这样做:

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

如前所述,merge将递归地合并您的文档及其嵌入文档/关系,并将它们标记为由 ODM 管理,就像刚刚获取它们一样。请注意,合并将符合您的级联设置以供参考。有关合并的更多信息可以在文档中找到。另请注意,合并文档可能会影响已获取的文档并使用正在合并的内容更新其字段。

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