简体   繁体   English

如何建立学说联系?

[英]How to set doctrine associations?

I know that association property in entity is implements \\Doctrine\\Common\\Collections\\Collection . 我知道实体中的关联属性是实现\\Doctrine\\Common\\Collections\\Collection I know that in constructor such properties should be initialized: 我知道在构造函数中应初始化此类属性:

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

I know that I can modify collections using ArrayCollection#add() and ArrayCollection#remove() . 我知道我可以使用ArrayCollection#add()ArrayCollection#remove()修改集合。 However I have a different case. 但是我有不同的情况。

Suppose I have a new simple array of associative entities. 假设我有一个新的关联实体简单数组。 Using existing methods I need to check every element in array: if entity collection has it. 使用现有方法,我需要检查数组中的每个元素:实体集合是否具有它。 If no - add array element to entity collection. 如果否-将数组元素添加到实体集合。 In addition to this, I need to check every element in entity collection. 除此之外,我需要检查实体集合中的每个元素。 If any collection element is absent in new array, then I need to remove it from collection. 如果新数组中没有任何集合元素,那么我需要将其从集合中删除。 So much work to do trivial thing. 要做很多琐碎的事情。

What I want? 我想要的是? To have the setProducts method implemented: 要实现setProducts方法:

class Entity {
  private $products;

  // ... constructor

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

I tried: $this->products = new ArrayCollection($products) . 我试过了: $this->products = new ArrayCollection($products) However this makes doctrine remove all products and add those ones from $products parameter. 但是,这会使主义删除所有产品,并从$products参数中添加这些$products I want similar result but without database queries. 我想要类似的结果,但没有数据库查询。

Is there any built in solution in Doctrine for such case? 在这种情况下,Doctrine中是否有任何内置解决方案?

Edit : I would like to have a method in ArrayCollection like fromArray which would merge elements in collections removing unneeded. 编辑 :我想在ArrayCollection有一个方法,例如fromArray ,它将合并不需要的集合中的元素。 This would just duplicate using add/remove calls for each element in collection argumen manually. 只需手动使用集合参数中的每个元素的add/remove调用进行复制。

Doctrine collections do not have a "merge"-feature that will add/remove entities from an array or Collection in another Collection. 原则集合没有“合并”功能,该功能将从另一个集合中的数组或集合中添加/删除实体。

If you want to "simplify" the manual merge process you describe using add/remove, you could use array_merge assuming both arrays are not numeric, but instead have some kind of unique key, eg the entity's spl_object_hash : 如果要“简化”使用添加/删除描述的手动合并过程,则可以使用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()
            )
        )
    );
}

You might want to use the product id instead of spl_object_hash as 2 products with the same id, but created as separate entities - eg one through findBy() in Doctrine and one manually created with new Product() - will be recognized as 2 distinct products and might cause another insert-attempt. 您可能要使用产品ID而不是spl_object_hash作为具有相同ID的2个产品,但是创建为单独的实体-例如,通过findBy()和使用new Product()手动创建的一个-将被识别为2个不同的产品并可能导致另一个插入尝试。

Since you replace the original PersistentCollection holding your previously fetched products with a new ArrayCollection this might still result in unneeded queries or yield unexpected results when flushing the EntityManager, though. 但是,由于用新的ArrayCollection替换了保存先前获取的产品的原始PersistentCollection,因此在刷新EntityManager时,这仍可能导致不必要的查询或产生意外结果。 Not to mention, that this approach might be harder to read than explicitly calling addElement/removeElement on the original Collection instead. 更不用说,与在原始Collection上显式调用addElement / removeElement相比,此方法可能更难阅读。

I would approach it by creating my own collection class that extends Doctrine array collection class: 我将通过创建自己的扩展了Doctrine数组集合类的集合类来解决这个问题:

use Doctrine\Common\Collections\ArrayCollection;

class ProductCollection extends ArrayCollection
{
}

In the entity itself you would initialise it in the __constructor : 在实体本身中,您可以在__constructor初始化它:

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

Here, Doctrine will you use your collection class for product results. 在这里,Doctrine您将使用您的集合类获取产品结果。 After this you could add your own function to deal with your special merge, perhaps something: 之后,您可以添加自己的函数来处理特殊的合并,也许是这样:

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

It will return a brand new product collection, that you can replace your other collection in the entity. 它将返回一个全新的产品集合,您可以替换实体中的其他集合。 However, if the entity is attached and under doctrine control, this will render SQL at the other end, if you want to play with the entity without risking database updates you need to detach the entity: 但是,如果该实体是附加的并且受原则控制,则它将在另一端呈现SQL,如果您想在不冒着数据库更新风险的情况下使用该实体,则需要分离该实体:

$entityManager->detach($productEntity);

Hopes this helps 希望这会有所帮助

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

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