使用Doctrine进行原始SQL查询

44

我需要使用一些非常复杂的查询来生成我的应用程序中的报告。 我正在使用Symfony作为我的框架,Doctrine作为我的ORM。

我的问题是:

如何最好地将高度复杂的SQL查询直接传递给Doctrine而不将它们转换为Doctrine查询语言? 我一直在阅读关于 Raw_SQL 扩展的文章,但似乎仍然需要按部就班地传递查询(例如 from())。 有没有可以只倾倒一堆原始SQL命令的方法?


抱歉打扰了,不过您用的是哪个工具/库来生成应用程序报告呢?最好的问候! - Rui Gonçalves
2
现在?只有SQL,原始的PHP和Gall。 :D - Levi Hackwith
6个回答

56
$q = Doctrine_Manager::getInstance()->getCurrentConnection();
$result = $q->execute(" -- RAW SQL HERE -- ");

请查看Doctrine API文档以获取不同的执行方法。


@simple:是的,您可以使用任何SQL。 - Tom
7
由于这个答案似乎很受欢迎,我应该补充一下,这种方法绕过了Doctrine提供的转义功能,所以要手动转义内容,否则可能会留下SQL注入漏洞。 - Tom
5
我认为这个回答是针对Doctrine版本<2的。对于Doctrine 2中的原始查询,我发现这篇帖子很有帮助:http://forum.symfony-project.org/viewtopic.php?f=23&t=37872。 - Jason Swett
我发现在@richsage的答案中添加->getDbh()可以防止启用Doctrine分析器时出现警告。 - cmc

41

是的。您可以使用以下代码从Doctrine获取数据库句柄:

$pdo = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();

然后按如下方式执行您的 SQL:

$query = "SELECT * FROM table WHERE param1 = :param1 AND param2 = :param2";
$stmt = $pdo->prepare($query);

$params = array(
  "param1"  => "value1",
  "param2"  => "value2"
);
$stmt->execute($params);

$results = $stmt->fetchAll();  

你可以像上面的例子一样使用绑定变量。

请注意,Doctrine不会自动将结果优雅地转化为记录对象等,因此您需要处理返回的结果作为数组,每行返回一个数组(列值作为键值对)。


有没有一种方法可以强制Doctrine通过PDO来填充我获取的结果?还是我只能使用我得到的内容工作? - Levi Hackwith
从记忆中来看,使用上面的方法不会自动进行,因为Doctrine不知道您有哪些列。如果您的列命名得足够好,我想您可以使用fromArray()或类似的方法,但数据需要重新格式化为可用的形式。 - richsage
如果可以的话,使用查询返回记录ID,然后使用简单的 $table->find($id) 加载它。 - lotsoffreetime

6

我不确定你说的原始SQL是什么意思,但可以通过以下方式执行传统的SQL查询:

... 
// $this->_displayPortabilityWarning();

$conn = Doctrine_Manager::connection();
$pdo = $conn->execute($sql);
$pdo->setFetchMode(Doctrine_Core::FETCH_ASSOC);
$result = $pdo->fetchAll();
...

下面的方法不是必需的,但它展示了一个好的实践。
protected function _displayPortabilityWarning($engine = 'pgsql')
{
     $conn = Doctrine_Manager::connection();
     $driver = $conn->getDriverName();

     if (strtolower($engine) != strtolower($driver)) {
        trigger_error('Here we have possible database portability issue. This code was tested on ' . $engine . ' but you are trying to run it on ' . $driver, E_USER_NOTICE);
     }
}

6
需要注意的是,Doctrine2使用PDO作为基础,因此我建议使用预处理语句而不是普通的execute。

示例:

$db = Doctrine_Manager::getInstance()->getCurrentConnection();
$query = $db->prepare("SELECT `someField` FROM `someTable` WHERE `field` = :value");
$query->execute(array('value' => 'someValue'));

这个问题涉及Symfony 1。在Symfony 1中,使用的是Doctrine 1.2 - 这个答案可能会引导错误。 - xmc
对不起,我并不是有意误导。不过此解决方案仍然有效,因为Symfony 1也可以与Doctrine一起使用。 - Nikola Petkanski

6
您可以使用Doctrine_RawSql()来创建原始SQL查询,这些查询将转换为Doctrine对象。

0

Symfony使用Doctrine插入原始SQL语句。

这是版本Symfoney 1.3中的操作。

$q = Doctrine_Manager::getInstance()->getCurrentConnection();
$result = $q->execute($query);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接