【问题标题】:Doctrine: DQL query without specifying class fully qualified name (FQN)Doctrine:不指定类完全限定名 (FQN) 的 DQL 查询
【发布时间】: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

标签: php symfony doctrine-orm dql


【解决方案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-&gt;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)的复合查询很难编写和阅读。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-15
      • 2020-11-12
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-25
      相关资源
      最近更新 更多