我有一个像这样的mysql表:
CREATE TABLE testtbl (
id INT(11) NOT NULL AUTO_INCREMENT,
field1 INT(11) NOT NULL DEFAULT '0',
field2 INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (id)
);
INSERT INTO testtbl (field1, field2) VALUES (1, 1);
我的phalcon项目中显示的模型是:
class Testtbl extends \Phalcon\Mvc\Model
{
public $id;
public $field1;
public $field2;
public function initialize() {
$this->setConnectionService('db');
$this->skipAttributes(array('field1'));
}
public function columnMap() {
return array(
'id' => 'id',
'field1' => 'field1',
'field2' => 'field2'
);
}
}
在我的控制器中我有
$model = new Testtbl();
$model->id=1;
$model->field2 = 2;
if ($model->update() === false) {
$msg = $model->getMessages();
print_r($msg);
}
db服务设置为在文件中记录查询。 执行控制器代码后,日志文件包含:
[][INFO] DESCRIBE `testtbl`
[][INFO] SELECT COUNT(*) "rowcount" FROM `testtbl` WHERE `id` = ?
[][INFO] UPDATE `testtbl` SET `field2` = ? WHERE `id` = ?
为什么在更新之前有选择?
如何在没有任何事先选择的情况下进行更新,仍然使用phalcon的模型? (我可以直接在Phalcon \ Db \ Adapter \ Pdo \ Mysql中执行查询,但不想这样做。)
(如果我 - >更新从 - > findFirst收到的模型,则不会有任何SELECT COUNT(*)“rowcount”..,只有当我直接进行更新时才会出现。)
答案 0 :(得分:2)
使用原始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;
}
}
我观看了我的PostgreSQL日志进行了4次测试:
没有MetaData使用Model-&gt; 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'
使用重写的Model-&gt; update()
没有MetaData2014-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-&gt; update()
的手动MetaData2014-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
使用覆盖模型的手动元数据 - &gt; 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语句。
答案 1 :(得分:1)
如果没有原始SQL,这是不可能的,因为如果不需要,Phalcon将不会更新记录。由于您正在创建一个新对象并使用主键填充它,因此您要强制Phalcon首先检查是否存在与您设置的ID匹配的实际记录。
这将为您提供以下选项:
编辑:
$model = new Testtbl();
$model->setReadConnectionService('master');
$model->id=1;
$model->field2 = 2;
$model->update();
这将确保describe语句(如果您没有模型元数据)和rowcount与具有最新数据的主数据库相对。
这会解决您的问题吗?
答案 2 :(得分:1)
在phalcon文档中,引用了验证消息InvalidUpdateAttempt。 当尝试更新记录但它不存在时产生。 我没有找到任何方法来抑制它的触发器,看起来没有,也许你会有更多的运气。