Doctrine分离、缓存和合并

10

我使用的是Doctrine 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);

当我从缓存中获取数据(使用Doctrine的APC缓存驱动程序)时,我执行以下操作:

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

我的希望是这样做能够重新启用实体上的关系加载,因为除了该查询中显示的内容之外,还有许多其他与用户对象相关联的关系。

我正在尝试创建一个新的实体,如下所示:

$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。听起来...不对。

1个回答

13

当合并用户时,您希望关联的公司和特权也被合并,是吗?

这个过程称为级联:

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

在您的用户实体中,对于$company和$privilege,在@ManyToOne注释(或其他类型的关联定义)中放置

如果您还想要级联分离调用(建议),则放置

p.s.:不要在一个关联的两端都放置这样的级联,否则会创建无限循环;)

编辑:

这段代码:

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

应该是:

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

merge() 的问题在于它不会改变你传递的参数实体,而是返回一个表示管理版本实体的对象。因此,你应该使用返回值,而不是传递的参数。


特权实际上是与用户的关系。因此,在公司和特权关系上都需要cascade={"detach", "merge"},对吗? - nwalke
请看我的更新。放置级联似乎没有产生任何效果。 - nwalke
嗨,我知道这是一个旧帖子,但我发现这种方法存在问题。我按照你所说的设置了所有内容,但我注意到在Doctrine的日志中,它也尝试更新与数据库中相同值合并的实体。如何避免这种情况?我使用了cascade={"detach", "merge"}作为级联。有什么建议吗?谢谢! - stuzzo
不过,你能否提出一个新的问题吗?因为你描述的是另一个问题。 - Jasper N. Brouwer
这里我们来看一下 :) 谢谢 http://stackoverflow.com/questions/23519983/doctrine-2-how-to-use-objects-retrieved-from-cache-in-relationships - stuzzo
直到我读到这个问题的最后一段,我花了整整一天的时间。有时候浏览阅读可能会很糟糕。:( 因此,我专门创建了一个关于这个主题的问题,以帮助其他遇到同样问题的人。在这里: http://stackoverflow.com/questions/27321682/associated-entity-not-merged-correctly/27321727#27321727 - Nelson Teixeira

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接