具有自引用ManyToMany的继承的实体:EXTRA_LAZY提取模式不起作用

时间:2018-10-07 06:38:04

标签: doctrine lazy-loading class-table-inheritance

我必须执行以下设置:父类

/**
 * @ORM\Entity()
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 */
abstract class DataCategory
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    //...
}

和几个派生类,这些派生类持有对父级的引用(此处仅显示一个)

/**
 * @ORM\Entity
 */
class MultiCompoundDataCategory extends DataCategory
{
    /**
     * @ORM\ManyToMany(targetEntity="DataCategory", fetch="EXTRA_LAZY")
     * @ORM\JoinTable(name="multi_compound_data_category_data_category",
     *      joinColumns={@ORM\JoinColumn(name="multi_compound_data_category", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="data_category", referencedColumnName="id")})
     */
    public $summands;


    public function __construct()
    {
        $this->summands = new ArrayCollection();
    }
}

现在通过加载所有MultiCompoundDataCategories时 $this->getDoctrine()->getRepository(MultiCompoundDataCategory::class)->findAll(),不仅会发出MultiCompoundDataCategories上的一个选择(在ManyToMany表上具有联接)。取而代之的是,我得到一个主要查询,接着对每个被补充的个查询,每个查询都有一个大的胖序列LEFT JOIN(也有the docs contain a warning关于这个问题,我大量引用非继承树的叶子节点)。

顺便说一句:LAZY是否已经为避免加载ManyToMany而足够了?

this comment开始,我认为问题在于我的子实体引用了父实体。我该如何规避?映射的超类?

1 个答案:

答案 0 :(得分:1)

好的,我发现了一些东西,但不知道是否存在更好的解决方案。

This blog帖子给了我解决方案的热情(最后一段)。

通过执行DQL提取联接,我可以热切地向子实体加载水合的引用。因此,我要做的是加载所有子类。

$all=[];
$all['sampled'] = $em->createQuery("SELECT s FROM ".SampledDataCategory::class." s")->getResult();
$all['compound'] = $em->createQuery("SELECT c, s, s2 FROM ".CompoundDataCategory::class." c JOIN c.cat1 s JOIN c.cat2 s2")->getResult();
$all['unary'] = $em->createQuery("SELECT u, s FROM ".UnaryDataCategory::class." u JOIN u.dataCategory s")->getResult();
$all['multi'] = $em->createQuery("SELECT m, s FROM ".MultiCompoundDataCategory::class." m JOIN m.summands s")->getResult();

此后,由于实体管理器已经看到了每个引用的DataCategory,因此不必进行许多SELECT查询。

这听起来很怪异,但是到目前为止,我的测试表明4个具有大量水化工作负载的查询的运行速度比800个单项选择要快得多。