使用原始 SQL 查询(如 eBrian 所述)对您没有帮助。您必须在模型中额外提供手动元数据 (see here) 以防止选择语句。
我使用 Testtbl 类在 metaData() 和 update() 函数中注释/注释进行了以下测试(在 postgresql 上)。
<?php
namespace Library\Storage;
use Phalcon\Db\Adapter\Pdo\Postgresql;
use Phalcon\Db\Column,
Phalcon\Mvc\Model\MetaData;
class Testtbl extends \Phalcon\Mvc\Model {
public $id;
public $field1;
public $field2;
public function metaData()
{
return array(
//Every column in the mapped table
MetaData::MODELS_ATTRIBUTES => array(
'id', 'field1', 'field2'
),
//Every column part of the primary key
MetaData::MODELS_PRIMARY_KEY => array(
'id'
),
//Every column that isn't part of the primary key
MetaData::MODELS_NON_PRIMARY_KEY => array(
'field1', 'field2'
),
//Every column that doesn't allows null values
MetaData::MODELS_NOT_NULL => array(
'id', 'field1', 'field2'
),
//Every column and their data types
MetaData::MODELS_DATA_TYPES => array(
'id' => Column::TYPE_INTEGER,
'field2' => Column::TYPE_INTEGER,
'field2' => Column::TYPE_INTEGER
),
//The columns that have numeric data types
MetaData::MODELS_DATA_TYPES_NUMERIC => array(
'id' => true,
'field1' => true,
'field2' => true,
),
//The identity column, use boolean false if the model doesn't have
//an identity column
MetaData::MODELS_IDENTITY_COLUMN => 'id',
//How every column must be bound/casted
MetaData::MODELS_DATA_TYPES_BIND => array(
'id' => Column::BIND_PARAM_INT,
'field1' => Column::BIND_PARAM_INT,
'field2' => Column::BIND_PARAM_INT
),
//Fields that must be ignored from INSERT SQL statements
MetaData::MODELS_AUTOMATIC_DEFAULT_INSERT => array(
'id' => true
),
//Fields that must be ignored from UPDATE SQL statements
MetaData::MODELS_AUTOMATIC_DEFAULT_UPDATE => array(
'id' => true
)
);
}
public function initialize() {
$this->setConnectionService('db');
$this->skipAttributes(array('field1'));
}
public function columnMap() {
return array(
'id' => 'id',
'field1' => 'field1',
'field2' => 'field2'
);
}
public function update($data=null, $whiteList=null) {
if($this->id > 0) {
$phql = 'UPDATE testtbl SET field1 = :f1, field2 = :f2 WHERE id = '.$this->id;
/** @var Postgresql $db */
$db = $this->getDI()->get('db');
$db->execute($phql, array('f1' => $this->field1, 'f2' => $this->field2));
} else {
throw new \UnexpectedValueException('ID is required for update');
}
return TRUE;
}
}
我进行了 4 次测试运行以查看我的 PostgreSQL 日志:
没有使用 Model->update() 的元数据
2014-01-30 20:30:11 CET LOG: statement: SET search_path TO 'public'
2014-01-30 20:30:11 CET LOG: execute pdo_stmt_00000001: SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM information_schema.tables WHERE table_schema = 'public' AND table_name='testtbl'
2014-01-30 20:30:11 CET LOG: statement: DEALLOCATE pdo_stmt_00000001
2014-01-30 20:30:11 CET LOG: execute pdo_stmt_00000002: SELECT DISTINCT c.column_name AS Field, c.data_type AS Type, c.character_maximum_length AS Size, c.numeric_precision AS NumericSize, c.numeric_scale AS NumericScale, c.is_nullable AS Null, CASE WHEN pkc.column_name NOTNULL THEN 'PRI' ELSE '' END AS Key, CASE WHEN c.data_type LIKE '%int%' AND c.column_default LIKE '%nextval%' THEN 'auto_increment' ELSE '' END AS Extra, c.ordinal_position AS Position FROM information_schema.columns c LEFT JOIN ( SELECT kcu.column_name, kcu.table_name, kcu.table_schema FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu on (kcu.constraint_name = tc.constraint_name and kcu.table_name=tc.table_name and kcu.table_schema=tc.table_schema) WHERE tc.constraint_type='PRIMARY KEY') pkc ON (c.column_name=pkc.column_name AND c.table_schema = pkc.table_schema AND c.table_name=pkc.table_name) WHERE c.table_schema='public' AND c.table_name='testtbl' ORDER BY c.ordinal_position
2014-01-30 20:30:11 CET LOG: statement: DEALLOCATE pdo_stmt_00000002
2014-01-30 20:30:11 CET LOG: execute pdo_stmt_00000003: SELECT COUNT(*) "rowcount" FROM "testtbl" WHERE "id" = $1
2014-01-30 20:30:11 CET DETAIL: parameters: $1 = '1'
没有使用覆盖模型的元数据->update()
2014-01-30 20:28:38 CET LOG: statement: SET search_path TO 'public'
2014-01-30 20:28:38 CET LOG: execute pdo_stmt_00000001: SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM information_schema.tables WHERE table_schema = 'public' AND table_name='testtbl'
2014-01-30 20:28:38 CET LOG: statement: DEALLOCATE pdo_stmt_00000001
2014-01-30 20:28:38 CET LOG: execute pdo_stmt_00000002: SELECT DISTINCT c.column_name AS Field, c.data_type AS Type, c.character_maximum_length AS Size, c.numeric_precision AS NumericSize, c.numeric_scale AS NumericScale, c.is_nullable AS Null, CASE WHEN pkc.column_name NOTNULL THEN 'PRI' ELSE '' END AS Key, CASE WHEN c.data_type LIKE '%int%' AND c.column_default LIKE '%nextval%' THEN 'auto_increment' ELSE '' END AS Extra, c.ordinal_position AS Position FROM information_schema.columns c LEFT JOIN ( SELECT kcu.column_name, kcu.table_name, kcu.table_schema FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu on (kcu.constraint_name = tc.constraint_name and kcu.table_name=tc.table_name and kcu.table_schema=tc.table_schema) WHERE tc.constraint_type='PRIMARY KEY') pkc ON (c.column_name=pkc.column_name AND c.table_schema = pkc.table_schema AND c.table_name=pkc.table_name) WHERE c.table_schema='public' AND c.table_name='testtbl' ORDER BY c.ordinal_position
2014-01-30 20:28:38 CET LOG: statement: DEALLOCATE pdo_stmt_00000002
2014-01-30 20:28:38 CET LOG: execute pdo_stmt_00000003: UPDATE testtbl SET field1 = $1, field2 = $2 WHERE id = 1
2014-01-30 20:28:38 CET DETAIL: parameters: $1 = '1', $2 = '2'
2014-01-30 20:28:38 CET LOG: statement: DEALLOCATE pdo_stmt_00000003
使用 Model->update() 手动元数据
2014-01-30 20:26:12 CET LOG: statement: SET search_path TO 'public'
2014-01-30 20:26:12 CET LOG: execute pdo_stmt_00000001: SELECT COUNT(*) "rowcount" FROM "testtbl" WHERE "id" = $1
2014-01-30 20:26:12 CET DETAIL: parameters: $1 = '1'
2014-01-30 20:26:12 CET LOG: statement: DEALLOCATE pdo_stmt_00000001
2014-01-30 20:26:12 CET LOG: execute pdo_stmt_00000002: UPDATE "testtbl" SET "field2" = $1 WHERE "id" = $2
2014-01-30 20:26:12 CET DETAIL: parameters: $1 = '2', $2 = '1'
2014-01-30 20:26:12 CET LOG: statement: DEALLOCATE pdo_stmt_00000002
使用覆盖模型的手动元数据->update()
2014-01-30 20:23:14 CET LOG: statement: SET search_path TO 'public'
2014-01-30 20:23:14 CET LOG: execute pdo_stmt_00000001: UPDATE testtbl SET field1 = $1, field2 = $2 WHERE id = 1
2014-01-30 20:23:14 CET DETAIL: parameters: $1 = '1', $2 = '2'
2014-01-30 20:23:14 CET LOG: statement: DEALLOCATE pdo_stmt_00000001
如您所见,发出单个更新查询的唯一方法是提供完整的元数据并将原始 SQL 语句与 pdo 一起使用。