代码之家  ›  专栏  ›  技术社区  ›  FreeLightman

如何设置条令关联?

  •  0
  • FreeLightman  · 技术社区  · 6 年前

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

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

    我知道我可以使用 ArrayCollection#add() ArrayCollection#remove() . 不过,我有一个不同的情况。

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

    我想要什么?拥有 setProducts 实现的方法:

    class Entity {
      private $products;
    
      // ... constructor
    
      public function setProducts(array $products)
      {
        // synchronize $products with $this->products
      }
    }
    

    我试过: $this->products = new ArrayCollection($products) . 然而,这使得条令删除所有产品,并添加这些产品从 $products

    对于这种情况,理论上有什么内在的解决办法吗?

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

    2 回复  |  直到 6 年前
        1
  •  0
  •   dbrumann    6 年前

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

    如果要“简化”使用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()
                )
            )
        );
    }
    

    spl\u对象\u哈希 作为两个具有相同id的产品,但创建为单独的实体-例如,一到 findBy() 在条令和一个手动创建的 new Product()

    但是,由于使用新的ArrayCollection替换包含以前获取的产品的原始PersistentCollection,因此在刷新EntityManager时仍可能导致不需要的查询或产生意外的结果。更不用说,这种方法可能比在原始集合上显式调用addElement/removeElement更难理解。

        2
  •  0
  •   Oli    6 年前

    我将通过创建自己的集合类来实现这一点,该集合类扩展了Doctrine数组集合类:

    use Doctrine\Common\Collections\ArrayCollection;
    
    class ProductCollection extends ArrayCollection
    {
    }
    

    在实体本身中,您可以在 __constructor :

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

    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;
    }
    

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

    $entityManager->detach($productEntity);
    

    希望这有帮助