无法从表单生成器中的存储库获取EntityManager

问题描述 投票:0回答:1

在 Symfony2 的表单类型中,我想包含一个带有查询生成器的实体字段,以便选择要显示的行。 我的查询很复杂,我无法找到使用查询生成器进行查询的方法,我想使用 DQL。 不幸的是,我不能做

$repository->createQuery(...)
也不能做
$repository->getEntityManager()->createQuery()
。只有
$repository->createQueryBuilder(...)
有效。 有办法解决这个问题吗?

顺便说一句,如果您碰巧找到一种更智能的方法来执行我的 SQL 请求,那将非常有用(但这不是本问题的主题!)

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $user = $this->user;
    $builder
        ->add('friend', 'entity',
            array(
                'class' => 'MyappUserBundle:User',
                'label' => 'User',
                'query_builder' => function(EntityRepository $repository) use ($user) {
                    $query = $repository->getEntityManager()->createQuery("
                        SELECT u
                            FROM MyappUserBundle:User u
                        WHERE
                            u.id NOT IN (SELECT friend FROM MyappUserBundle:Friendrequest WHERE user = :user)
                        AND 
                            u.id NOT IN (SELECT user FROM MyappUserBundle:Friendrequest WHERE friend = :user)
                        AND 
                            u.id != :user
                        ")
                        ->setParameter('user', $user)
                        ;

                    return $query;
                }
                )
            )
        ;
}
php symfony doctrine dql formbuilder
1个回答
6
投票

如何解决

query_builder
问题(以及一般问题)

我们知道我们可以访问您实体的

EntityRepository
类。因此我们可以很容易地找到哪些方法是可公开访问的。

因此,我们可以在 Google 上搜索“doctrine api entityrepository”,这会引导我们找到doctrine 站点上的 EntityRepository 类 API 文档

在该页面上,我们可以找到哪种方法是公开访问的,您可以找到 3 种创建查询的方法,其中之一是

createNativeNamedQuery

根据文档,该方法返回一个

Doctrine\ORM\NativeQuery
的实例,点击它会进入另一个具有其他方法的页面。您可以看到
NativeQuery
有一个
setQuery
方法,并继承自
Doctrine\ORM\AbstractQuery
一系列其他方法。

现在,我们可能拥有所需的所有信息,因此我们可以提出一个可能有效的解决方案(如果不起作用,那么我们可能真的非常接近了)。

// The closure expects \Doctrine\ORM\QueryBuilder to be returned
// so we need to create a named query first then create a list of ids
// and pass it to a query builder.
'query_builder' => function(EntityRepository $repository) use ($user) {
    // Query for user ids with sub queries
    $results = $repository
        ->createNativeNamedQuery('u')
        ->setSQL("
            SELECT u.id
            FROM user AS u
            WHERE u.id NOT IN (
                SELECT friend FROM friend_request_table WHERE user = :user
            )
            AND u.id NOT IN (
                SELECT user FROM friend_request_table WHERE friend = :user
            )
            AND u.id != :user
        ")
        ->setParameter('user', $user->getId())
        ->getArrayResult();

    // Build an array of IDs
    $ids = array_map(function ($row) {
        return $row['id'];
    }, $results);

    // Returns a QueryBuilder
    return $repository->createQueryBuilder('u')
        ->where('u.id IN (:ids)')
        ->setParameter('ids', $ids);
}

缺点是执行了两个查询。闭包期望返回

QueryBuilder
,因此我们需要首先创建一个原始查询,然后将结果传递给
QueryBuilder

最重要的是,本机查询意味着原始 SQL 查询,因此您不能使用实体注释,而且您的查询可能不支持跨不同的数据库。

如果您愿意我的意见,我认为您可以重构您的查询并删除子查询。删除子查询并将其结果作为参数传递将允许您使用 DQL,从而支持更多类型的数据库。

© www.soinside.com 2019 - 2024. All rights reserved.