Doctrine,如何将关系的所有对象添加到QueryBuilder的结果中,并实际显示添加对象的内容?
Doctrine, how to add all objects of the relationship to the result of the QueryBuilder and actually show the content of the added objects?
我的数据库中有以下结构:
每栋房子都有多个卧室和多个厨房。每个厨房都有多个橱柜。
现在,我获得了基于给定卧室的所有橱柜(我知道这很奇怪)。所以我进入一间卧室,它查找房子,获取与该房子相关的所有厨房,然后是这些厨房的所有橱柜。这是它的代码:
public function findCabinetsByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
我想扩展我的代码以包含每个橱柜甚至房子的厨房。我通过简单地在我的代码中添加 ->addSelect('kitchen')
来设法获得厨房。因此:
public function findCabinetsAndTheirKitchenByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->addSelect('kitchen')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
但是尝试添加 Kitchen 的 House 信息并没有以同样的方式工作,我想这与 Cabinets 与 House 没有直接关系这一事实有关。如果我使用最新的方法(又名 findCabinetsAndTheirKitchenByBedroom
),Xdebug 会显示以下内容:
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {App\Entity\Kitchen} [3]
▼house = {Proxies\__CG__\App\Entity\House} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\House*bedroom = null
*App\Entity\House*id = 555
*App\Entity\House*name = null
id = 55
country = "US"
当我使用第一个(又名findCabinetsByBedroom
)时反对这个:
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {Proxies\__CG__\App\Entity\Kitchen} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\Kitchen*house = null
*App\Entity\Kitchen*id = 55
*App\Entity\Kitchen*country = null
因此,根据这些结果,我得出结论 addSelect
确实归还了厨房。是的,我检查了数据库中的数据,这是正确的结果。但是如何将众议院信息添加到内阁?
还有一个问题,尽管 Xdebug 为每个橱柜显示了正确的厨房信息,但由于某种原因,在使用 POSTMAN 或浏览器进行测试时,它们没有返回。我得到以下结果:
{ "id": 1, "time": { "date": "2019-06-12 11:51:22.000000", "timezone_type": 3, "timezone": "UTC" }, "productCategory": "someCat", "kitchen": {} }
所以由于某种原因它是空的。关于如何在 Object Kitchen 中显示信息的任何想法?我认为这与它是一个不同于 Cabinet 的对象有关,但按照这个逻辑,time
的内容也应该是空的,因为它是一个 DateTime
对象。所以那不可能,但我不知道为什么它返回为空。
使用 Doctrine 时,默认加载与其他实体对象的关联 "LAZY",请参阅有关 Extra lazy associations 的文档:
With Doctrine 2.1 a feature called Extra Lazy is introduced for associations. Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed. [..]
(我会说,关于默认抓取设置的文档非常缺乏,因为这是我唯一能找到的地方(升级文档))
这意味着什么:如果您有类似以下注释的内容,则意味着关系在被调用之前不会被包括在内,例如通过 getObject()
或 getCollection()
/**
* @var Collection|Bathroom[]
* @ORM\OneToMany(targetEntity="Entity\Bathroom", mappedBy="house")
*/
private $bathrooms;
在这种情况下,当您获得 House
对象时,在执行期间检查对象(即使用 Xdebug)将显示 $house
确实 有 $bathrooms
,但是,每个实例将显示为:
{
id: 123,
location: null,
house: 2,
faucets: null,
shower: null,
__initialized__:false
}
这个对象的存在表明 Doctrine 知道浴室与房子相关联(因此后面的 'n' 第四个 ID 被设置在双向关系上,但没有设置其他属性),但是, __initialized__:false
表示 Doctrine 没有获取对象。因此:fetch="LAZY"
。
要获得与您的 get*()
操作的关联,必须将它们设置为 fetch="EAGER"
,如 here in the docs 所示。
Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.
要解决您的问题:
立即将您希望return的关联标记为fetch="EAGER"
额外:
看看Annotations Reference, specifically for OneToOne, OneToMany, ManyToOne and ManyToMany。这些参考资料还显示了每个关联类型可用的 fetch
选项。
我的数据库中有以下结构:
每栋房子都有多个卧室和多个厨房。每个厨房都有多个橱柜。
现在,我获得了基于给定卧室的所有橱柜(我知道这很奇怪)。所以我进入一间卧室,它查找房子,获取与该房子相关的所有厨房,然后是这些厨房的所有橱柜。这是它的代码:
public function findCabinetsByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
我想扩展我的代码以包含每个橱柜甚至房子的厨房。我通过简单地在我的代码中添加 ->addSelect('kitchen')
来设法获得厨房。因此:
public function findCabinetsAndTheirKitchenByBedroom(Bedroom $bedroom)
{
return $this->createQueryBuilder('cabinet')
->join('cabinet.kitchen', 'kitchen')
->join('kitchen.house', 'house')
->join('house.bedroom', 'bedroom')
->select('cabinet')
->addSelect('kitchen')
->andWhere('bedroom = : bedroom')
->setParameter('bedroom', $bedroom)
->getQuery()
->getResult(Query::HYDRATE_OBJECT);
}
但是尝试添加 Kitchen 的 House 信息并没有以同样的方式工作,我想这与 Cabinets 与 House 没有直接关系这一事实有关。如果我使用最新的方法(又名 findCabinetsAndTheirKitchenByBedroom
),Xdebug 会显示以下内容:
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {App\Entity\Kitchen} [3]
▼house = {Proxies\__CG__\App\Entity\House} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\House*bedroom = null
*App\Entity\House*id = 555
*App\Entity\House*name = null
id = 55
country = "US"
当我使用第一个(又名findCabinetsByBedroom
)时反对这个:
▼$cabinet = {array} [2]
▼0 = {App\Entity\Cabinet} [4]
id = 1
►time = {DateTime} [3]
productCategory = "someCat"
▼kitchen = {Proxies\__CG__\App\Entity\Kitchen} [7]
lazyPropertiesDefaults = {array} [0]
►__initializer__ = {Closure} [3]
►__cloner__ = {Closure} [3]
__isInitialized__ = false
*App\Entity\Kitchen*house = null
*App\Entity\Kitchen*id = 55
*App\Entity\Kitchen*country = null
因此,根据这些结果,我得出结论 addSelect
确实归还了厨房。是的,我检查了数据库中的数据,这是正确的结果。但是如何将众议院信息添加到内阁?
还有一个问题,尽管 Xdebug 为每个橱柜显示了正确的厨房信息,但由于某种原因,在使用 POSTMAN 或浏览器进行测试时,它们没有返回。我得到以下结果:
{ "id": 1, "time": { "date": "2019-06-12 11:51:22.000000", "timezone_type": 3, "timezone": "UTC" }, "productCategory": "someCat", "kitchen": {} }
所以由于某种原因它是空的。关于如何在 Object Kitchen 中显示信息的任何想法?我认为这与它是一个不同于 Cabinet 的对象有关,但按照这个逻辑,time
的内容也应该是空的,因为它是一个 DateTime
对象。所以那不可能,但我不知道为什么它返回为空。
使用 Doctrine 时,默认加载与其他实体对象的关联 "LAZY",请参阅有关 Extra lazy associations 的文档:
With Doctrine 2.1 a feature called Extra Lazy is introduced for associations. Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed. [..]
(我会说,关于默认抓取设置的文档非常缺乏,因为这是我唯一能找到的地方(升级文档))
这意味着什么:如果您有类似以下注释的内容,则意味着关系在被调用之前不会被包括在内,例如通过 getObject()
或 getCollection()
/**
* @var Collection|Bathroom[]
* @ORM\OneToMany(targetEntity="Entity\Bathroom", mappedBy="house")
*/
private $bathrooms;
在这种情况下,当您获得 House
对象时,在执行期间检查对象(即使用 Xdebug)将显示 $house
确实 有 $bathrooms
,但是,每个实例将显示为:
{
id: 123,
location: null,
house: 2,
faucets: null,
shower: null,
__initialized__:false
}
这个对象的存在表明 Doctrine 知道浴室与房子相关联(因此后面的 'n' 第四个 ID 被设置在双向关系上,但没有设置其他属性),但是, __initialized__:false
表示 Doctrine 没有获取对象。因此:fetch="LAZY"
。
要获得与您的 get*()
操作的关联,必须将它们设置为 fetch="EAGER"
,如 here in the docs 所示。
Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.
要解决您的问题:
立即将您希望return的关联标记为fetch="EAGER"
额外:
看看Annotations Reference, specifically for OneToOne, OneToMany, ManyToOne and ManyToMany。这些参考资料还显示了每个关联类型可用的 fetch
选项。