我有一个与ManyToMany相关联的字段,而我正处于这样一种情况:我只是试图获取所有ID而不保护字段中的任何子实体。
我知道在我访问该字段时会有一个查询来获取实体引用,这很好/期望。但是我需要遍历ID,但我不知道如何在不执行的情况下获取它们
$ids = [];
foreach($mainEntity->getSubEntities() as $subentity) {
$ids[] = $subentity->getId();
}
由于foreach
循环,这似乎也会自动给子实体加水。这会导致大量不必要的查询并影响页面加载时间。
我的子实体字段也标有EXTRALAZY
。
/**
* @var ArrayCollection
* @ORM\ManyToMany(targetEntity="User", fetch="EXTRA_LAZY")
* @ORM\JoinTable(name="user_friends")
*/
protected $friends;
答案 0 :(得分:6)
由于getKeys()仅返回PersistentCollection的顺序索引,因此我找到了该oneliner作为解决方案:
$myCollectionIds = $myCollection->map(function($obj){return $obj->getId();})->getValues();
在IN
上下文中顺利运行。
答案 1 :(得分:1)
我不认为使用实体定义实体的方式来做您是不可能的。 Doctrine PersistentCollection类将始终进行初始化,并在对其进行迭代或映射时从DB加载所有实体。如前所述,在map和getIterator的实现中可以看到,它是在foreach循环或闭包中运行代码之前完成的。
即使将集合标记为Extra Lazy,只要您使用contains,containsKey,count,get或slice以外的任何方法,所有内容都将从DB装入。
但是,如果您不介意稍微调整实体结构,则可以得到所需的行为。
Reify将ManyToMany关联为一个实体。
您的关系称为friend
,因此您可以创建一个friendship
实体:
/** @Entity */
class Frendship
{
/**
* @var int
* @Id @Column(type="integer") @GeneratedValue
**/
protected $id;
/**
* @var User
* @ORM\@ManyToOne(targetEntity="User", inversedBy="friendships")
**/
protected $friendA
/**
* @var User
* @ORM\@ManyToOne(targetEntity="User", inversedBy="friendships")
**/
protected $friendB
public function getOtherFriend(User $friend){
if ($this->friendA === $friend)) {
return $this->friendB;
} else if ($this->friendB === $friend)) {
return $this->friendA
} else {
throw new \Exception("$friend is not part of this friendship");
}
}
}
然后,您可以将friends
集合替换为frendships
集合并进行遍历。友谊将被完全水化,但这没关系,因为它们仅包含两个整数。
您可以从每个友谊中获取另一个朋友,它将成为一个代理对象,除非它恰好已被加载。由于您只想在其上调用getId()
,因此不需要从数据库中检索完整实体。