0

我有一个文档,该文档具有另一个文档的 ReferenceMany 属性。引用设置正常,数据从查询返回正常,但 arraycollection 中的每个文档都作为代理返回。在这个网站上,我看到有人提到我应该添加->prime(true)以返回实际引用的文档。

当返回文档的 ArrayCollection 时,我正在运行一个已提交给服务器的 id 循环,以将它们从引用的集合中删除。该removeElement方法不起作用 b/c 返回的文档是代理,我正在比较实际文档与那些代理。所以基本上我正在尝试:

  1. 查找单个文档
  2. 强制ReferenceMany属性中的所有文档为实际文档而不是代理文档
  3. 循环遍历我的 id 数组并加载每个文档
  4. 将文档发送到 removeElement 方法

在下面的第一个getSingleResult查询方法中,我收到一个错误cannot modify cursor after beginning iteration。我在这个网站上看到一个帖子提到你应该初始化结果,以便获取实际文档而不是代理,在他的示例中,他使用了getSingleResult.

$q = $this->dm->createQueryBuilder('\FH\Document\Person')->field('target')->prime(true)->field('id')->equals($data->p_id);
$person = $q->getQuery()->getSingleResult();

foreach($data->loc_id as $loc) {
    $location = $this->dm->createQueryBuilder('\FH\Document\Location')->field('id')->equals(new \MongoId($loc))->getQuery()->getSingleResult();
    $person->removeTarget($location);
}

....
....
....
public function removeTarget($document)
{
    $this->target->removeElement($document);

    return $this;
}

如果我->prime(true)从第一个查询中删除,它不会引发错误,但它实际上并没有删除任何元素,即使我在方法上设置断点,比较两个文档,并且数据完全相同,除了$this->target它们是Location代理文档,加载的是一个实际的Location文档。

我可以以某种方式启动单个结果,以便我可以ArrayCollection正确使用这些方法,还是我需要做一些 for 循环并比较 id?

更新

所以这是一个显示我遇到的问题的更新。虽然下面的解决方案只使用 MongoId(s),但当我提交一个实际的 Document 类时,它从未真正删除该文档。ArrayCollection 作为 PersistentCollection 从 Doctrine 中返回。中的每个元素$this->coll都属于此 Document 类型:

DocumentProxy\__CG__\FH\Document\Location

实际的文件是这样的:

FH\Document\Location

removeElement方法执行这样的array_search:

public function removeElement($element)
{
    $key = array_search($element, $this->_elements, true);

    if ($key !== false) {
        unset($this->_elements[$key]);

        return true;
    }

    return false;
}

所以因为对象类型并不完全相同,即使代理对象应该是从我创建的实际 Document 继承的,也$key总是返回 0(false),因此不会删除该元素。两个文档之间的所有内容都完全相同,除了对象类型。

就像我说的,我想我可以通过 MongoId 来做到这一点,但是为什么不能通过提交整个对象来工作呢?

4

1 回答 1

1

暂时不要担心主要(真实)的东西。所做的只是告诉教条现在提取引用的数据,因此当您遍历游标时,它不必多次调用数据库。

我要做的是更改您的 removeTarget 方法以执行以下操作。

$this->dm->createQueryBuilder('\FH\Document\Person')->field('id')->equals($data->p_id);
$person = $q->getQuery()->getSingleResult();
$person->removeTargets($data->loc_id);

人.php

public function removeTargets($targets)
{
    foreach ($targets as $target) {
        $this->removeTarget($target);
    }
}

public function removeTarget($target)
{
    if ($target instanceof \FH\Document\Location) {
        return $this->targets->removeElement($target);
    }

    foreach ($this->targets as $t) {
        if ($t->getId() == $target) {
            return $this->targets->removeElement($t);
        }
    }
    return $this;
}

这意味着您不必手动执行第二个查询,因为当您迭代它时,教义会知道它需要提取该引用上的数据。然后,您可以通过使用 prime(true) 调用使其在一次调用中提取所需的信息而不是在请求对象时动态执行此操作,从而加快此操作。

于 2012-11-23T11:41:56.510 回答