Published on

doctrine教程11---原始 SQL 查询

原创文章,转载时需取得本人同意并注明来源
Authors
  • Name
    langziyang
    Twitter

QueryBuilder 使用起来很有趣而且功能强大。但是,如果您正在编写一个超级复杂的查询,可能很难弄清楚如何将其转换为 QueryBuilder 格式,那我们也可以写原始SQL。

首先我们获取connection对象:

$conn = $this->getEntityManager()->getConnection();

Doctrine库实际上是两个主要部分。首先有一个较低级别的部分,称为“DBAL”,它代表“数据库抽象库”。它充当 PHP 原生 PDO 的包装器,并在其之上添加了一些功能。

Doctrine 的第二部分是我们到目前为止所处理的:它是更高级别的部分,称为“ORM”或“对象关系映射器”。这时您可以通过选择类和属性进行查询......并获取对象。

对于这个原始 SQL 查询,我们将直接处理较低级别的 Connection 对象。

        $conn = $this->getEntityManager()->getConnection();
        $sql = 'SELECT * FROM fortune_cookie';
        $stmt = $conn->prepare($sql);
        $result = $stmt->executeQuery();
        dd($result->fetchAllAssociative());

我们先取得Connect对象,准备了一条sql,然后创建一个Statement对象,然后执行查询,最后返回实际数据,然后返回了数组给我们, 然后我们用原始sql重写countNumberPrintedForCategory中的代码

        $conn = $this->getEntityManager()->getConnection();
        $sql = 'SELECT SUM(fortune_cookie.number_printed) AS fortunesPrinted, AVG(fortune_cookie.number_printed) fortunesAverage, category.name FROM fortune_cookie INNER JOIN category ON category.id = fortune_cookie.category_id WHERE fortune_cookie.category_id = :category';
        $stmt = $conn->prepare($sql);
        $result = $stmt->executeQuery([
        'category'=>$category->getId()
]);
        dd($result->fetchAllAssociative());

最大的区别就是我们在使用原始sql时,需要描述关联条件,并且可以看到,在sql中没有直接写fortune_cookie.category_id =具体的值,这是为了防止SQL注入,所以使用了占位, 并且在executeQuery传了id而不是category对象

刷新看一下,完全没有问题,写原始sql可能比较麻烦,但是如果你的查询足够复杂,请毫不犹豫地尝试这个。

顺便说一句,我们可以不使用 executeQuery() 传递 category ,而是用 $stmt->bindValue() 替换它,将 category 绑定到 $category->getId() 。这会给我们带来和以前一样的结果,所以你自己决定吧。

        $conn = $this->getEntityManager()->getConnection();
        $sql = 'SELECT SUM(fortune_cookie.number_printed) AS fortunesPrinted, AVG(fortune_cookie.number_printed) fortunesAverage, category.name FROM fortune_cookie INNER JOIN category ON category.id = fortune_cookie.category_id WHERE fortune_cookie.category_id = :category';
        $stmt = $conn->prepare($sql);
        $stmt->bindValue('category', $category->getId());
        $result = $stmt->executeQuery();
        dd($result->fetchAllAssociative());

但是,现在返回的是一个二维数组。我们真正想做的是只返回一个结果的关联数组。没问题:使用 fetchAssociative() 代替 fetchAllAssociative()

但是我们如何把数组转换为之前的对象呢?很简单 只需要返回对象然后把结果展开就行

$conn = $this->getEntityManager()->getConnection();
        $sql = 'SELECT SUM(fortune_cookie.number_printed) AS fortunesPrinted, AVG(fortune_cookie.number_printed) fortunesAverage, category.name as categoryName FROM fortune_cookie INNER JOIN category ON category.id = fortune_cookie.category_id WHERE fortune_cookie.category_id = :category';
        $stmt = $conn->prepare($sql);
        $stmt->bindValue('category',$category->getId());
        $result = $stmt->executeQuery();
        return new CategoryFortuneStats(...$result->fetchAssociative());