我必须执行以下设置:父类
/**
* @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开始,我认为问题在于我的子实体引用了父实体。我该如何规避?映射的超类?
答案 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个单项选择要快得多。