在 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;
}
)
)
;
}
如何解决
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,从而支持更多类型的数据库。