Doctrine:不指定 class 完全限定名 (FQN) 的 DQL 查询

Doctrine: DQL query without specifying class fully qualified name (FQN)

有没有办法在不指定 class 的完全限定名称的情况下编写 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 项目,查询在存储库中 class。我有一个 Doctrine XML 定义的实体,一个实体和实体存储库也在 XML 中定义,但我总是需要显式定义 FQN,有什么想法吗?

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,我深表歉意,但我还没有看到有人提到 DBAL QueryBuilder。

这是您在存储库 class 中使用 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

Doctrine offers a way to alias entity namespaces to simpler, shorter names to be used in DQL queries or for Repository access.

您可以在.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

假设您的存储库 class 扩展 \Doctrine\ORM\EntityRepository

你试过类似的东西吗?

return $this->getEntityManager()
       ->createQuery('SELECT i FROM '.$this->getEntityName().' i where i.id = :id')
       ->setParameter('id',1)
       ->getResult();