繁体   English   中英

如何建立学说联系?

[英]How to set doctrine associations?

我知道实体中的关联属性是实现\\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参数中添加这些$products 我想要类似的结果,但没有数据库查询。

在这种情况下,Doctrine中是否有任何内置解决方案?

编辑 :我想在ArrayCollection有一个方法,例如fromArray ,它将合并不需要的集合中的元素。 只需手动使用集合参数中的每个元素的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相比,此方法可能更难阅读。

我将通过创建自己的扩展了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;
}

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

$entityManager->detach($productEntity);

希望这会有所帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM