使用原始SQL查詢(如eBrian提到的)不會幫助你。您必須在模型中額外提供手動元數據(see here)以防止選擇語句。
我在進行metaData()和update()函數的Testtbl類註釋時做了以下測試(在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日誌:
沒有元數據使用型號 - > 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()的手動MetaData
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
正如你可以看到,發出一個單獨的更新查詢的唯一辦法是提供全面PDO元和使用原始的SQL語句。
findFirst對我來說不是一個選項,因爲它仍然會進行選擇。當模型在模型中使用setReadConnectionService('slave_server')和setWriteConnectionService('master_server')時,問題會有另一個含義。 如果從服務器位於主服務器(滯後)之後,無論出於何種原因,更新將永遠丟失,因爲它們不會進入複製二進制日誌。 – aconrad
是的,這確實爲問題增添了新的動態。我道歉,我沒有答案。我要撤回這個答案。 – brian
不要:)迄今是我從任何地方得到的唯一答案 – aconrad