Doctrine:不指定类完全限定名 (FQN) 的 DQL 查询
Posted
技术标签:
【中文标题】Doctrine:不指定类完全限定名 (FQN) 的 DQL 查询【英文标题】:Doctrine: DQL query without specifying class fully qualified name (FQN) 【发布时间】:2020-11-26 12:10:41 【问题描述】:有没有办法在不指定类的完全限定名的情况下编写 DQL 查询?
有没有办法创建以下查询:
return $this->getEntityManager()->createQuery(
'SELECT i
FROM Company\AccountingBundle\Entity\Invoice i
WHERE i.id = :id'
)->setParameter('id', 1)
->getResult();
像这样:
use Company\AccountingBundle\Entity\Invoice;
....
return $this->getEntityManager()->createQuery(
'SELECT i
FROM Invoice i
WHERE i.id = :id'
)->setParameter('id', 1)
->getResult();
或类似的东西。我真的会避免在 DQL 中设置完整的 FQN。
但我没有找到任何“setClass”或其他方法来执行此操作。
编辑上下文
实际上,它是一个 Symfony 项目,查询位于 Repository 类中。我有一个实体的Doctrine XML定义,一个实体和实体存储库也在XML中定义,但我总是需要明确定义FQN,有什么想法吗?
【问题讨论】:
可以使用字符串拼接:$work_class="Company\AccountingBundle\Entity\Invoice"; return $this->getEntityManager()->createQuery( 'SELECT i FROM ' . $work_class . ' i WHERE i.id = :id' )->setParameter('id', 1) ->getResult();
别想了,用heredoc或sprintf
构建您的查询字符串,然后将Invoice::class
传递给占位符值。
另一种方法是使用存储库,因为存储库始终与实体绑定,因此您无需明确声明它们。但我不知道您的应用程序的状态或要求,所以这需要您进行研究。
@El_Vanja 感谢您的评论,您是对的,我没有解释上下文!我的错。事实上,它是一个 Symfony 项目,查询位于 Repository 类中。我有一个实体的Doctrine XML定义,一个实体和实体存储库也在XML中定义,但我总是需要明确定义FQN,有什么想法吗?
您是否查看过您的 Doctrine 配置中的 alias 参数?官方例子here
【参考方案1】:
Doctrine 提供了一种将实体命名空间别名为更简单、更短的名称的方法,以便在 DQL 查询或存储库访问中使用。
您可以在.yaml的Doctrine配置中设置实体命名空间的别名
doctrine:
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
Company:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Company/AccountingBundle/Entity'
prefix: 'App\Company\AccountingBundle\Entity'
alias: AC
然后在 DQL 中,您可以使用“AC:Invoice”:
return $this->getEntityManager()->createQuery(
'SELECT i
FROM AC:Invoice i
WHERE i.id = :id'
)->setParameter('id', 1)
->getResult();
参考文献
Symfony bundle Mapping Configuration
Symfony Doctrine ORM Configuration
【讨论】:
【参考方案2】:假设您的存储库类扩展 \Doctrine\ORM\EntityRepository
你试过类似的东西吗?
return $this->getEntityManager()
->createQuery('SELECT i FROM '.$this->getEntityName().' i where i.id = :id')
->setParameter('id',1)
->getResult();
【讨论】:
【参考方案3】:Doctrine 方法是使用实体存储库。如果您的实体配置为绑定到存储库,例如:
/**
* @ORM\Entity(repositoryClass=InvoiceRepository::class)
*/
class Invoice
然后在该存储库中,如果您使用查询生成器,则该实体是 automatically tied to the query:
$qb = $this->createQueryBuilder('i') // 'i' is just an alias here
->where('i.id = :id')
->setParameter('id', $id);
要查看它提供的所有选项,您可以在查询生成器here 上阅读更多信息。
快速替代方案(不包括 Doctrine 功能),出于演示目的,我将留在这里:
1.使用sprintf
$q = sprintf('SELECT * FROM %s WHERE id = :id', Invoice::class);
return $this->getEntityManager()
->createQuery($q)
->setParameter('id', 1)
->getResult();
2。使用HEREDOC
语法
$entity = Invoice::class;
$q = <<<SQL
SELECT *
FROM $entity
WHERE id = :id
SQL;
return $this->getEntityManager()
->createQuery($q)
->setParameter('id', 1)
->getResult();
在这两种情况下,查询变量的输出都是SELECT * FROM App\Entity\Invoice WHERE id = :id
。
请注意,您必须为HEREDOC
初始化一个变量,因为它不能直接评估Invoice::class
。该选项绝对适用于较长的查询(特别是因为它突出显示 SQL 关键字),而 sprintf
可用于简短、直接的查询。
【讨论】:
好的,总而言之,使用 DQL 无法做到这一点。遗憾的是,QueryBuilder 允许自动检索实体,但不使用 DQL 语法。目前,唯一的方法是像其他人的建议一样更换课程。我会等几天,看看其他人是否会出现另一个想法。在所有情况下都感谢您。 @sdespont 查询构建器在内部将其转换为 DQL,如果需要,您可以获取使用$dql = $qb->getDql();
构建的内容。如果您特别想编写 DQL,那么是的,我的想法很新鲜。也许会有更多了解教义的人出现。无论如何都欢迎你。【参考方案4】:
如果您明确需要 DQL,我深表歉意,但我没有看到有人提到 DBAL QueryBuilder。
这是您的查询,在 Repository 类中,使用 DBAL QueryBuilder:
return $this->getEntityManager()
->getConnection() //
->createQueryBuilder() // This is different query builder that doesn't automatically assume Entity
->select('i')
->from('invoice', 'i') // Specify the table
->where('i.id = :id') // Rest of the syntax should be similar to DQL but you need to query against table columns, not properties (like in DQL) - for example, in DQL: ... where('firstName = :firstName') ... in DBAL: where('first_name = :firstName')
->setParameter('id', 1)
->execute()->fetchAllAssociative(); // Double check if you can fetch as stdClass
无论如何,DBAL QueryBuilder 与 Doctrine Query Builder 的不同之处在于更接近数据库层。
关于 DBAL QueryBuilder 的更多信息:https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html#sql-query-builder
【讨论】:
谢谢,但我真的很想使用 DQL。原因是因为对于不每天都使用这种语法的人来说,具有连接和嵌套条件 AND / OR(包括 AND)的复合查询很难编写和阅读。以上是关于Doctrine:不指定类完全限定名 (FQN) 的 DQL 查询的主要内容,如果未能解决你的问题,请参考以下文章