Orm 单表继承关联问题(总是与文档相反地急于加载))

Orm 单表继承关联问题(总是与文档相反地急于加载)),orm,symfony1,doctrine,doctrine-orm,single-table-inheritance,Orm,Symfony1,Doctrine,Doctrine Orm,Single Table Inheritance,我对单表继承有一个问题,我不确定我是否正确解释了文档 首先:我没有在这里详细复制我的代码/实体映射(甚至没有使用正确的语法),因为我认为可以更好地抽象地传达问题。 如果这是不可接受的,请说这样的话,我会添加完整的代码-但它很长,我想我的问题可以回答没有它 如果有帮助的话,我可以画画 一个ER图,试图传达我正在尝试做的事情。 如果你读了下面的内容并认为“嘿,这应该行得通”,那么告诉我,我会上传真正的代码 第二:我不在任何地方使用延迟加载。在访问我的实体之前,我确保通过预先编写DQL来加载我将要访问

我对单表继承有一个问题,我不确定我是否正确解释了文档

首先:我没有在这里详细复制我的代码/实体映射(甚至没有使用正确的语法),因为我认为可以更好地抽象地传达问题。 如果这是不可接受的,请说这样的话,我会添加完整的代码-但它很长,我想我的问题可以回答没有它

如果有帮助的话,我可以画画 一个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查询的数量(一个)。 这一切都很好(相当标准的东西)

这设置了我的集合,意味着我可以遍历它,而无需发出额外的查询

问题:

我已经在我的应用程序的其他地方映射了其他实体-非常类似于此(注:我的总体问题与下面的问题非常相似,但有一个主要区别(见下文)

然后,我通过修改初始实体来实现双向关系

// @entity trainingDepartment
     oneToMany: animalTrainer
     oneToOne: building
     oneToOne: departmentAward
     fields: [capacity]
// @entity animalTrainer
     fields: [name / age / qualification]
     oneToOne: trainerAward
发生了什么

现在,当我以与上面完全相同的方式访问我的原始实体时,它们会自动(急切地)加载关联实体以获得奖励,尽管我没有告诉它们。 当我迭代一大堆培训部门/动物培训人员,并且条令为每个实体执行SQL语句时,这尤其糟糕

对于每个部门有10名培训师的20个部门,这是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个实体与最低级别的实体相关联 而不是“奖励”基类,那么他们应该能够使用代理,而不是急于加载实体

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';
    }
}
这是一个与我描述的相反的问题

相关理论文件

有一场一般性的表演 单表考虑 继承:如果使用STI实体 作为多对一或一对一实体 你永远不应该使用其中一个 学校上层的班级 继承层次结构 “目标实体”,只有那些 没有子类,否则就没有规则 无法创建此服务器的代理实例 实体,并将始终加载该实体 急切地

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


再次:我可以发布真实的代码-但考虑到问题的长度,我觉得最好不要发布。任何输入都非常受欢迎。

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


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

奇怪的是,我现在发现,如果我将实体之间的关系创建为oneToMany,它不会急于加载。我只是暂时通过实体映射进行了更改。是否需要进行关联是双向的?您的应用程序能否仅处理奖励实体上的关联?不幸的是,我可以。奖励实体的另一侧有一个完整的层次结构,我通常从该层次结构开始业务逻辑(为了参数起见,将其称为awardIssuer)注意:类名已更改-我不是在制作一个关于动物训练的应用程序:-)。是双向性导致了这个问题吗?正如我所说,我刚刚将关系重新定义为1:N(也是双向的),并将代码中的1:1作为临时修复(如果这有意义的话)。这似乎奏效了……也感谢您几个月前在前一个问题上的帮助-从那时起我的理解有了很大进步:-)先生,您是位绅士,感谢您花时间理解我的问题并给我一个知情的答案。我现在可以在2.1特性列表的“Persister重构”下看到这一点。我想我可以保留我的垫片,直到2.1发布。
//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')";