如何设定学说联想?

问题描述 投票:0回答:2

我知道实体中的关联属性是实现\Doctrine\Common\Collections\Collection。我知道在构造函数中应该初始化这样的属性:

$this->collection = new \Doctrine\Common\Collections\ArrayCollection()

我知道我可以使用ArrayCollection#add()ArrayCollection#remove()修改集合。但是我有一个不同的情况。

假设我有一个新的简单关联实体数组。使用现有方法,我需要检查数组中的每个元素:if entity collection是否具有它。如果不是 - 将数组元素添加到实体集合中。除此之外,我还需要检查实体集合中的每个元素。如果新数组中没有任何集合元素,那么我需要将其从集合中删除。这么多工作要做琐碎的事情。

我想要的是?要实施setProducts方法:

class Entity {
  private $products;

  // ... constructor

  public function setProducts(array $products)
  {
    // synchronize $products with $this->products
  }
}

我试过了:$this->products = new ArrayCollection($products)。然而,这使得doctrine删除所有产品并从$products参数中添加那些产品。我想要类似的结果,但没有数据库查询。

对于这种情况,Doctrine中是否有内置的解决方案?

编辑:我想在ArrayCollection中有一个方法,如fromArray,它会合并集合中的元素,删除不需要的。这将只是使用add/remove调用手动复制集合中的每个元素。

php symfony doctrine
2个回答
0
投票

Doctrine集合没有“合并”功能,可以在另一个Collection中添加/删除数组或Collection中的实体。

如果你想“简化”你使用add / remove描述的手动合并过程,你可以使用array_merge,假设两个数组都不是数字,而是有一些独特的键,例如实体的spl_object_hash

public function setProducts(array $products)
{
    $this->products = new ArrayCollection(
        array_merge(
            array_combine(
                array_map('spl_object_hash', $this->products->toArray()),
                $this->products->toArray()
            ),
            array_combine(
                array_map('spl_object_hash', $products),
                $products->toArray()
            )
        )
    );
}

您可能希望使用产品ID而不是spl_object_hash作为具有相同ID的2个产品,但创建为单独的实体 - 例如一个通过学说中的findBy()和一个用new Product()手动创建的 - 将被识别为2个不同的产品,并可能导致另一次插入尝试。

由于您使用新的ArrayCollection替换保存以前提取的产品的原始PersistentCollection,但在刷新EntityManager时,这可能仍会导致不必要的查询或产生意外结果。更不用说,这种方法可能比在原始Collection上显式调用addElement / removeElement更难阅读。


0
投票

我会通过创建我自己的扩展Doctrine数组集合类的集合类来实现它:

use Doctrine\Common\Collections\ArrayCollection;

class ProductCollection extends ArrayCollection
{
}

在实体本身中,您将在__constructor中初始化它:

public function __construct()
{
    $this->products = new ProductCollection();
}

在这里,Doctrine会将您的集合类用于产品结果。在此之后你可以添加自己的函数来处理你的特殊合并,也许是:

public function mergeProducts(ProductCollection $products): ProductCollection
{
    $result = new ProductCollection();
    foreach($products as $product) {
        $add = true;
        foreach($this->getIterator() as $p) {
            if($product->getId() === $p->getId()) {
                $result->add($product);
                $add = false;
            }
        }
        if($add) {
            $result->add($product);
        }
    }
    return $result;
}

它将返回一个全新的产品系列,您可以在实体中替换您的其他系列。但是,如果实体是附加的并且在doctrine控制下,这将在另一端呈现SQL,如果您想要在不冒数据库更新风险的情况下使用实体,则需要分离实体:

$entityManager->detach($productEntity);

希望这会有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.