【问题标题】:Get only list of ID's from ManyToMany with Doctrine使用 Doctrine 仅从 ManyToMany 获取 ID 列表
【发布时间】:2015-07-14 07:22:30
【问题描述】:

我有一个 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;

【问题讨论】:

    标签: php mysql symfony doctrine-orm


    【解决方案1】:

    由于 getKeys() 只返回 PersistentCollection 的顺序索引,我发现这个 oneliner 作为解决方案:

    $myCollectionIds = $myCollection->map(function($obj){return $obj->getId();})->getValues();
    

    IN 上下文中运行顺畅。

    【讨论】:

    • 这不是仍然会为集合中的所有实体补充水分吗? PersistentCollection 从 AbstractLazyCollection 继承 map 和 it starts with $this->initialize()
    • 该死,你是对的。当 map() 方法运行时,集合被初始化,即使只收到了 ID。
    • 是的,我一直在寻找一种方法来让集合仅填充代理对象,但我没有找到。
    • 我已经发布了对这个问题的不同答案。
    【解决方案2】:

    我不相信用实体定义的方式来做你想做的事是可能的。 Doctrine PersistentCollection 类将始终初始化自身,当您迭代或映射它时从数据库中加载所有实体。它在运行 foreach 循环或闭包中的代码之前执行此操作,如您在 mapgetIterator 的实现中所见。

    即使集合被标记为Extra Lazy,只要您使用除 contains、containsKey、count、get 或 slice 之外的任何方法,内容也会全部从数据库加载。

    但是,如果您不介意稍微调整实体结构,您可以获得您想要的行为。

    ReifyManyToMany 关联成一个实体。

    您的关系称为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");
            }
        }
    }
    

    然后你可以用frendships 集合替换你的friends 集合并遍历它。友谊将完全水合,但没关系,因为它们只包含两个整数。

    您可以从每个好友中获取另一个好友,它将是一个代理对象,除非它恰好已经被加载。由于您只想调用getId(),因此原则上不需要从数据库中检索完整的实体。

    【讨论】:

    • 我已经意识到我上面的代码不能正常工作,因为 User 类上的友谊关系需要 mappedBy 的两个不同值,这是不可能的。不过可能有类似的解决方案,也许是通过拥有两个单独的友谊集合,其中用户在一个所有友谊的 A 侧,在另一个友谊的 B 侧。
    猜你喜欢
    • 2017-10-14
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多