【问题标题】:Doctrine's QueryBuilder returns unexpected Proxies\__CG__\ objectsDoctrine Query Builder 返回意外的 Proxies\____\ 对象
【发布时间】:2015-03-08 11:19:46
【问题描述】:

我正在尝试加入 2 个具有一对一关系的简单表。我的问题是查询生成器返回的原始结果是一个由 2 种不同类型的对象组成的数组:

Proxies\__CG__\Azphotos\PhotoBundle\Entity\PhotoCategories
Azphotos\PhotoBundle\Entity\PhotoGallery

我只想在结果中包含Azphotos\PhotoBundle\Entity\PhotoGallery 类型的对象。

表格“photo_gallery”:

CREATE TABLE `photo_gallery` (
  `aid` int(10) NOT NULL AUTO_INCREMENT,
  `string_id` varchar(255) DEFAULT NULL,
  `title` varchar(255) NOT NULL DEFAULT '',
  `main_category_id` int(11) NOT NULL,
  `photographer_id` mediumint(9) DEFAULT NULL,
  `main_media` varchar(255) DEFAULT NULL,
  `content` text NOT NULL,
  `date_taken` date DEFAULT NULL,
  `place_taken` varchar(255) DEFAULT NULL,
  `tags` varchar(255) DEFAULT NULL,
  `position` int(11) NOT NULL,
  `allow_comments` enum('true','false') NOT NULL DEFAULT 'true',
  `active` enum('true','false') NOT NULL DEFAULT 'true',
  `views` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`aid`),
  KEY `main_category_id` (`main_category_id`),
  CONSTRAINT `photo_gallery_ibfk_1` FOREIGN KEY (`main_category_id`) REFERENCES `photo_categories` (`aid`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=336 DEFAULT CHARSET=utf8;

表格“photo_categories”:

CREATE TABLE `photo_categories` (
  `aid` int(10) NOT NULL AUTO_INCREMENT,
  `string_id` varchar(255) DEFAULT NULL,
  `head_category` int(11) NOT NULL,
  `title` varchar(255) NOT NULL DEFAULT '',
  `state` varchar(255) DEFAULT NULL,
  `country` varchar(255) NOT NULL,
  `content` text NOT NULL,
  `position` int(11) NOT NULL,
  `tags` varchar(255) DEFAULT NULL,
  `active` enum('true','false') NOT NULL DEFAULT 'true',
  PRIMARY KEY (`aid`)
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8;

如您所见,photo_gallery.main_category_id 字段是对 photo_categories.aid 的 FK 引用。 PhotoGallery.orm.xml 中的架构片段引用此关系:

<one-to-one field="mainCategory" target-entity="PhotoCategories">
    <join-columns>
       <join-column name="main_category_id" referenced-column-name="aid"/>
    </join-columns>
</one-to-one>

来自 PhotoGallery 实体的片段:

/**
 * PhotoGallery
 *
 * @ORM\Table(name="photo_gallery", indexes={@ORM\Index(name="main_category_id", columns={"main_category_id"})})
 * @ORM\Entity(repositoryClass="Azphotos\PhotoBundle\Entity\PhotoGalleryRepository")
 */
class PhotoGallery
{

    /**
     * @var \Azphotos\PhotoBundle\Entity\PhotoCategories
     *
     * @ORM\OneToOne(targetEntity="Azphotos\PhotoBundle\Entity\PhotoCategories")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="main_category_id", referencedColumnName="aid")
     * })
     */
    private $mainCategory;

我有一个 PhotoGalleryRepository 类,我在其中使用查询生成器来连接这两个表:

public function findLatest($params, $keyword = false, $filter_by = false) {
    [...some irrelevant code here...]

    $qb = $this->createQueryBuilder('photoGallery');
    $qb->select(array('photoGallery', 'photoCat'))
        ->innerJoin(
            'Azphotos\PhotoBundle\Entity\PhotoCategories',
            'photoCat',
            \Doctrine\ORM\Query\Expr\Join::WITH,
            'photoGallery.mainCategory = photoCat.aid'
        )
        ->where('photoGallery.active = ?1')
        ->andWhere('photoCat.active = ?2');

    [...some irrelevant code here...]

    $qb->setParameter(1, 'true')
        ->setParameter(2, 'true')
        ->orderBy($params['orderBy'], 'DESC');

    if (isset($params['offset']) && isset($params['limit'])) {
        $qb->setFirstResult($params['offset'])->setMaxResults($params['limit']);
    }

    try {
        $result = $qb->getQuery()->getResult();

        $resultRevised = array();
        foreach ($result AS $photo) {
             //this is the lame part
            if (get_class($photo) == 'Azphotos\PhotoBundle\Entity\PhotoGallery') {
                $resultRevised[] = $photo;
            }
        }

        return $resultRevised;
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }
}

如你所见,我正在循环访问 $result = $qb-&gt;getQuery()-&gt;getResult();只包含 Azphotos\PhotoBundle\Entity\PhotoGallery 类型的对象。

当我查看使用 Symfony2 分析器运行的查询时,我发现原生 MySQL 查询是绝对正确的。

为什么我的原始结果被 Proxies\__CG__\Azphotos\PhotoBundle\Entity\PhotoCategories 对象污染了,我在这里做错了什么?

非常感谢任何帮助。

【问题讨论】:

  • 您可以将延迟加载的代理视为您的实体。代理扩展了您的实体类,因此它甚至可以通过instanceof 检查。只要您在代理上调用 getter 方法,它就会对对象进行水合。或者,您可以将查询配置为仅返回完全水合的对象。
  • 是的。我可以在代理类上调用任何 getter,它会返回正确的结果。在这种情况下,它将是 PhotoCategory 实体的任何属性。我感到困惑的是,为什么在我的结果中我得到了两个实体的混合(其中一个被表示为代理)。得到结果后,我没有直接查询 PhotoCategory 实体,而是通过 PhotoGallery,例如:$photo->getMainCategory()->getTitle()。如果我将我的选择更改为 $qb->select(array('photoGallery')),它只会返回photoGallery 对象,但在每次调用 $photo->getMainCategory()->getTitle() 时,它都会执行额外的数据库查询。
  • 我的结果中的这种“混合”是否是预期的行为?
  • 是的,这是预期的结果。查询的根实体将是您的实体类的完全水合实例,并且所有关联的实体将是代理,直到在需要 Doctrine 水合代理的代理类上调用 getter。在代理上调用 getter 后,Doctrine 查询数据库并用实体的完全水合实例替换代理。希望这是有道理的,很难简明扼要地解释。

标签: symfony doctrine-orm


【解决方案1】:

据我所知,当我们为该存储库类(在您的情况下为照片库存储库)编写 DQL 时,关联实体(在您的情况下为照片类别)是延迟加载到代理类上的。因此,这可能就是您获得代理类的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多