如何在加载产品时自动加载其关联的streams数据?
你之前监听ProductEvents::PRODUCT_LOADED_EVENT的思路存在问题:该事件触发时,产品主表数据已经完成数据库查询、实体实例化流程,此时已经无法触发Doctrine的关联预加载逻辑,如果在事件回调中循环调用$product->getStreams(),会产生严重的N+1查询问题,产品数量较多时页面性能会大幅下降。
针对你需要的产品页、分类页场景,直接在产品查询的Criteria构建阶段添加上streams关联即可,底层会自动完成关联数据的联表预加载,后续直接调用$product->getStreams()就能拿到完整关联数据,无额外查询开销。
具体实现
创建事件订阅者,监听产品详情页、产品列表页的Criteria构建事件,统一添加streams关联:
<?php declare(strict_types=1); namespace CustomPlugin\Subscriber; use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent; use Shopware\Core\Content\Product\Events\ProductPageCriteriaEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ProductLoadSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ProductPageCriteriaEvent::class => 'appendStreamsAssociation', ProductListingCriteriaEvent::class => 'appendStreamsAssociation', ]; } public function appendStreamsAssociation(ProductPageCriteriaEvent|ProductListingCriteriaEvent $event): void { $event->getCriteria()->addAssociation('streams'); } }
给该订阅者正确配置服务标签(Shopware 6版本默认自动加载src/Subscriber目录下的订阅者,无需手动配置),清除缓存后即可生效,产品页、分类页加载产品时会自动关联查询streams数据,直接调用$product->getStreams()即可获取完整数据,不需要通过扩展属性中转。
扩展:全场景自动加载
如果你需要在所有产品加载场景(包括后台、API、第三方插件查询产品数据)都自动加载streams关联,不需要每次查询手动加关联,可以通过CompilerPass修改产品实体的Doctrine元数据定义,将streams关联的加载模式调整为EAGER,加载产品主表数据时会自动带上关联的streams数据。
注意:全场景EAGER加载会给所有产品相关的查询增加额外联表开销,非必要不推荐使用,优先使用定向页面加关联的方案。
内容的提问来源于stack exchange,提问作者Alphaegen

