我知道实体中的关联属性是实现\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
参数中添加了这些产品。我想要类似的结果,但没有数据库查询。
在这种情况下,Doctrine中是否有内置解决方案?
修改:
我想在ArrayCollection
中有一个像fromArray
的方法,该方法将合并集合中的元素以删除不需要的元素。只需手动使用add/remove
调用集合实参中的每个元素来重复。
答案 0 :(得分:0)
Doctrine集合没有“合并”功能,该功能将从一个数组或另一个集合中的集合中添加/删除实体。
如果您想“简化”使用添加/删除描述的手动合并过程,则可以使用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
用作2个具有相同ID,但创建为单独实体的产品-例如,在Doctrine中使用一个到findBy()
并使用new Product()
手动创建的一个-将被识别为2种不同的产品,并可能导致另一个插入尝试。
由于您用新的ArrayCollection替换了保存先前获取的产品的原始PersistentCollection,因此这可能仍然会导致不必要的查询或在刷新EntityManager时产生意外结果。更不用说,与在原始Collection上显式调用addElement / removeElement相比,此方法可能更难阅读。
答案 1 :(得分: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;
}
它将返回一个全新的产品集合,您可以替换实体中的其他集合。但是,如果该实体已附加并受原则控制,则它将在另一端呈现SQL,如果您想在不冒着数据库更新风险的情况下使用该实体,则需要分离该实体:
$entityManager->detach($productEntity);
希望这会有所帮助