【问题标题】:Execute raw SQL using Doctrine 2使用 Doctrine 2 执行原始 SQL
【发布时间】:2011-03-20 11:52:49
【问题描述】:

我想使用 Doctrine 2 执行原始 SQL

我需要截断数据库表并使用默认测试数据初始化表。

【问题讨论】:

  • 顺便说一句,当我想做自动化的数据库工作时,比如做mysqldumps 或从以前的转储或删除表中加载数据,我通常会为此工作编写一个 shell 脚本,然后编写执行 shell 脚本的任务(或“命令”,在 Symfony2 语言中)。据我所知,ORM 的目的是抽象出重复的工作,如果你正在做一些像截断表格这样的事情,我不明白把 Doctrine 带入画面有什么意义,因为 Doctrine 没有不要让这项任务变得更容易。

标签: php sql doctrine


【解决方案1】:

Doctrine DBAL 2.13 以来,这里的大多数答案现在都已弃用。例如,execute is deprecated and fetchAll will be removed in 2022

/**
 * BC layer for a wide-spread use-case of old DBAL APIs
 *
 * @deprecated This API is deprecated and will be removed after 2022
 *
 * @return list<mixed>
 */
public function fetchAll(int $mode = FetchMode::ASSOCIATIVE): array

不再推荐使用execute,然后是fetchAll,因为两者都已弃用。

* @deprecated Statement::execute() is deprecated, use Statement::executeQuery() or executeStatement() instead

* @deprecated Result::fetchAll is deprecated, and will be removed after 2022

所以在执行原始 SQL 和获取结果时,我们必须更加具体。


我们需要使用executeQueryexecuteStatement,而不是使用Statement::execute()

executeQuery 返回对象Result:

使用当前绑定的参数执行语句并返回 结果。

executeStatement返回int

使用当前绑定的参数执行语句并返回受影响的行。


我们需要使用fetchAllNumericfetchAllAssociative (and more),而不是使用Result::fetchAll()


要获得简单的结果,您必须这样做:

public function getSqlResult(EntityManagerInterface $em)
{   
    $sql = " 
        SELECT firstName,
               lastName
          FROM app_user
    ";

    $stmt = $em->getConnection()->prepare($sql);
    $result = $stmt->executeQuery()->fetchAllAssociative();
    return $result;
}   

并带有参数:

public function getSqlResult(EntityManagerInterface $em)
{   
    $sql = " 
        SELECT firstName,
               lastName,
               age
          FROM app_user
          where age >= :age
    ";

    $stmt = $em->getConnection()->prepare($sql);
    $stmt->bindParam('age', 18);
    $result = $stmt->executeQuery()->fetchAllAssociative();
    return $result;
}   

【讨论】:

    【解决方案2】:

    你不能,Doctrine 2 不允许原始查询。看起来你可以,但如果你尝试这样的事情:

    $sql = "SELECT DATE_FORMAT(whatever.createdAt, '%Y-%m-%d') FORM whatever...";
    $em = $this->getDoctrine()->getManager();
    $em->getConnection()->exec($sql);
    

    Doctrine 会吐出一个错误,指出 DATE_FORMAT 是一个未知函数。

    但是我的数据库(mysql)确实知道这个函数,所以基本上,Doctrine 正在后台(和你背后)解析那个查询,并找到一个它不理解的表达式,考虑到查询是无效。

    因此,如果您像我一样希望能够简单地将字符串发送到数据库并让其处理(并让开发人员对安全性承担全部责任),那就别管它了。

    当然,您可以编写一个扩展程序以某种方式实现这一点,但您最好使用 mysqli 来执行此操作,并将 Doctrine 留给它的 ORM 业务。

    【讨论】:

      【解决方案3】:

      假设您使用的是 PDO,我通过这样做使其工作。

      //Place query here, let's say you want all the users that have blue as their favorite color
      $sql = "SELECT name FROM user WHERE favorite_color = :color";
      
      //set parameters 
      //you may set as many parameters as you have on your query
      $params['color'] = blue;
      
      
      //create the prepared statement, by getting the doctrine connection
      $stmt = $this->entityManager->getConnection()->prepare($sql);
      $stmt->execute($params);
      //I used FETCH_COLUMN because I only needed one Column.
      return $stmt->fetchAll(PDO::FETCH_COLUMN);
      

      您可以更改 FETCH_TYPE 以满足您的需要。

      【讨论】:

      【解决方案4】:

      这是我正在做的 Doctrine 2 中的原始查询示例:

      public function getAuthoritativeSportsRecords()
      {   
          $sql = " 
              SELECT name,
                     event_type,
                     sport_type,
                     level
                FROM vnn_sport
          ";
      
          $em = $this->getDoctrine()->getManager();
          $stmt = $em->getConnection()->prepare($sql);
          $stmt->execute();
          return $stmt->fetchAll();
      }   
      

      【讨论】:

      • 不错的答案。要在此代码中获取实体管理器,您可以使用 $this->getDoctrine()->getManager() 代替上面的代码 "$this->getEntityManager()" b>,这种方式对我很有效。
      • 嘿,它给了我调用未定义方法 Index::getDoctrine() 我应该怎么做
      • 我正在使用 codeigniter 和学说 2 wildlyinaccurate.com/integrating-doctrine-2-with-codeigniter-2
      • 这使我朝着正确的方向前进,但这并不是我所需要的。我怀疑答案的年龄会有所不同。我用过:...getConnection()-&gt;query($sql); 并且不必运行$stmt-&gt;execute();
      • 请注意,使用 Symfony4 和自动装配,您可以输入提示 EntityManagerInterface $entityManager,然后调用 $entityManager-&gt;getConnection()
      【解决方案5】:

      在您的模型中创建原始 SQL 语句(下面的示例是我必须使用但替换您自己的日期间隔的示例。如果您正在执行 SELECT 添加 ->fetchall() 到 execute() 调用。

         $sql = "DELETE FROM tmp 
                  WHERE lastedit + INTERVAL '5 minute' < NOW() ";
      
          $stmt = $this->getServiceLocator()
                       ->get('Doctrine\ORM\EntityManager')
                       ->getConnection()
                       ->prepare($sql);
      
          $stmt->execute();
      

      【讨论】:

        【解决方案6】:
        //$sql - sql statement
        //$em - entity manager
        
        $em->getConnection()->exec( $sql );
        

        【讨论】:

        • 调用 prepare() 而不是 exec 也是一个好主意,这样您仍然可以获得准备好的语句支持。
        • $em->getConnection()->executeQuery($sql) 现在 :-)
        • 已弃用execexecutefetchAllDoctrine DBAL >2.13see my answer for more information. 中已弃用
        【解决方案7】:

        如何执行原始查询并返回数据。

        挂上你的经理并建立新的联系:

        $manager = $this->getDoctrine()->getManager();
        $conn = $manager->getConnection();
        

        创建您的查询并 fetchAll:

        $result= $conn->query('select foobar from mytable')->fetchAll();
        

        像这样从结果中获取数据:

        $this->appendStringToFile("first row foobar is: " . $result[0]['foobar']);
        

        【讨论】:

        • query() 用于当 SQL 返回一些你想使用的数据时; exec() 用于当它没有的时候
        • 已弃用execexecutefetchAllDoctrine DBAL >2.13see my answer for more information. 中已弃用
        【解决方案8】:

        我发现答案大概是:

        NativeQuery 可让您执行本机 SQL,根据映射结果 你的规格。这样一个 描述如何的规范 SQL 结果集映射到一个 Doctrine 结果由 a 表示 结果集映射。

        来源:Native SQL

        【讨论】:

        • 这是公认的答案,但我仍然看不出这部分 Doctrine 有什么用处,因为您总是需要 ResultSetMapping。我不希望它把结果映射到实体……这默认了运行任意 SQL 的点!
        • @MikeMurko 我发现这篇文章有助于在 Doctrine 2 中运行原始查询:forum.symfony-project.org/viewtopic.php?f=23&t=37872
        • 另外,非本地本地 SQL 不会执行所有可能的 SQL 查询。 DELETE/UPDATE/INSERT 不起作用,某些不遵循原则假设的表定义也不起作用。 (没有 id 的 M2M 连接表)。所以这个答案并不普遍。也不应该被接受,因为 INSERT 不起作用。
        【解决方案9】:

        我遇到了同样的问题。您想查看实体管理器提供的连接对象:

        $conn = $em->getConnection();
        

        然后您可以直接对其进行查询/执行:

        $statement = $conn->query('select foo from bar');
        $num_rows_effected = $conn->exec('update bar set foo=1');
        

        http://www.doctrine-project.org/api/dbal/2.0/doctrine/dbal/connection.html查看连接对象的文档

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-16
          • 1970-01-01
          • 2017-04-08
          • 1970-01-01
          • 2018-06-17
          • 2014-12-18
          • 2014-06-06
          相关资源
          最近更新 更多