Doctrine ORM单表继承关联问题(总是Eager加载与文档相反))

时间:2011-06-17 00:18:06

标签: orm symfony1 doctrine doctrine-orm single-table-inheritance

我遇到单表继承问题,我不确定我是否正确解释文档。

首先:我没有在这里详细复制我的代码/实体映射(甚至使用正确的语法),因为我认为可以更好地抽象地传达问题。  如果这一切都不能接受,那么我会添加完整的代码 - 但它很长,我想我的问题可以在没有它的情况下得到解答。

如果有帮助我可以画画  一个ER图,试图传达我正在尝试做的事情。  如果您阅读以下内容并认为“嘿那应该有用” - 然后告诉我,我将上传真实代码

第二:我不在任何地方使用延迟加载。在访问我的实体之前,我确保通过预先编写DQL来加载我将要访问的每个相关实体 - 所以以下问题对我的应用程序来说是相当终端的)

设置:

我有一些实体 - 这些构成了我的应用程序的核心。

// @entity AnimalTrainingSchool
//   oneToMany: trainingDepartment
     fields: [name / location / year founded]
// @entity trainingDepartment
     oneToMany: animalTrainer
     oneToOne: building
     fields: [capacity]
// @entity animalTrainer
     fields: [name / age / qualification]

我经常在不同的环境中访问它们 - 但我通常会迭代这些实体的级别和访问属性和关系。

foreach ($animalTrainingSchool as $school){
    echo $school->getName() . ' at ' . $school->getLocation();
    echo 'These are the training departments for this school:';
    foreach ($school->getTrainingDepartments as $trainingDepartment){
        echo $trainingDepartment->getAnimalTypeTrained() . ' are trained in this department';
    }
}

我确保通过形成我的DQL并执行它来预先加载所有这些 - 以限制SQL查询的数量(到一个)。 这一切都很好(相当标准的东西)。

DQL Example : "SELECT ats, td, at FROM AnimalTrainingSchool ats JOIN AnimalTrainingSchool.trainingDepartments td JOIN td.animalTrainer at";

这会设置我的收藏并意味着我可以遍历它而无需发出其他查询

问题:

我已经在我的应用程序的其他地方绘制了其他参与者 - 与此非常类似(注意:我的整体问题与下面的问题非常相似,只有一个主要区别(见下文)

Doctrine 2 Inheritance Mapping with Association

// NB: new awards are issued each time they are awarded - so it is meant to be a oneToOne relationships - the awards are unique
// @entity award
     {id information / table information / discriminator map / inheritance type (SINGLE_TABLE)}
     fields: [medalMaterial / award_serial_number]
//departmentAward extends award
    oneToOne: trainingDepartment
//trainerAward extends award
    oneToOne: animalTrainer

然后我通过修改我的初始实体使双向关系

// @entity trainingDepartment
     oneToMany: animalTrainer
     oneToOne: building
     oneToOne: departmentAward
     fields: [capacity]
// @entity animalTrainer
     fields: [name / age / qualification]
     oneToOne: trainerAward

发生了什么

现在当我以与上面完全相同的方式访问我的原始实体时 - 尽管我没有告诉他们,但他们会自动(急切地)为他们的奖励加载相关实体。 当我迭代一堆trainingDepartments / AnimalTrainers和Doctrine正在为每个实体执行一个SQL语句时,这尤其糟糕。

对于20个部门,每个部门有10名培训师 - 这是另外200个查询。

//Given the exact same DQL and foreach loop as above (note that at no stage am I accessing awards) - I get a ton of extra queries that look like this

"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN trainingDepartmentTable ON award.awardee_id = trainingDepartmentTable.id and award.discriminatorColumn IN ('departmentAward')";
// or...
"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN animalTrainerTable ON award.awardee_id = animalTrainerTable.id and award.discriminatorColumn IN ('trainerAward')";

所生成的内容都不正确 - 只是在阅读了以下问题后,在我看来,就像我在文档描述中设置的那样(并且与@Matthieu相反;即 - 如果我相关我最初的3个人参加了最低级别的实体 而不是“奖励”基类,那么他们应该能够使用代理而不是试图急切地加载实体。

Stackoverflow问题与我所描述的内容相反

Doctrine 2 Inheritance Mapping with Association

相关学说文档

http://www.doctrine-project.org/docs/orm/2.0/en/reference/inheritance-mapping.html#performance-impact

  

有一般表现   考虑单表   继承:如果使用STI实体   作为多对一或一对一的实体   你永远不应该使用其中一个   上层的课程   继承层次为   “targetEntity”,只有那些   没有子类。否则主义   无法创建此代理实例   实体并将始终加载实体   热切。

在我看来,无论您是否加入基础级实体或子类实体 - Doctrine都会急切地加载关联,并且不会尝试使用代理。

再说一遍:我可以发布实际代码 - 但考虑到问题的长度,我觉得最好不要。任何输入都非常感激。

1 个答案:

答案 0 :(得分:4)

oneToOne关系的反面不能延迟加载。为了支持延迟加载,Doctrine需要创建一个代理对象,但代理对象需要有一个与之关联的标识符。在oneToOne关系的情况下,标识符仅在拥有方可用。因此必须急切地加载反向关系。

如果可能,您应该尝试获取加入这些关联。版本2.1将自动强制获取反向oneToOne关系的连接。