2014-01-19 33 views
0

之前,我有一個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); 

因爲它出現在我的爾康的項目我的型號是:

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」..只有當我直接進行更新時纔會出現。)

回答

2

使用原始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語句。

1

沒有原始SQL,這是不可能的,因爲Phalcon不會更新記錄(如果不需要)。由於您正在創建一個新對象並使用主鍵填充它,因此您要強制Phalcon首先檢查是否存在與您設置的ID匹配的實際記錄。

這將使您以下選項:

  • 使用原始SQL
  • 的FindFirst()的記錄,修改內容,並調用update()或save()

編輯:

$model = new Testtbl(); 
$model->setReadConnectionService('master'); 
$model->id=1; 
$model->field2 = 2; 
$model->update(); 

這將確保描述語句(如果您沒有模型元數據)和r owcount是針對主數據庫與最新的數據。

這是否解決您的問題?

+0

findFirst對我來說不是一個選項,因爲它仍然會進行選擇。當模型在模型中使用setReadConnectionService('slave_server')和setWriteConnectionService('master_server')時,問題會有另一個含義。 如果從服務器位於主服務器(滯後)之後,無論出於何種原因,更新將永遠丟失,因爲它們不會進入複製二進制日誌。 – aconrad

+0

是的,這確實爲問題增添了新的動態。我道歉,我沒有答案。我要撤回這個答案。 – brian

+0

不要:)迄今是我從任何地方得到的唯一答案 – aconrad

1

在phalcon文檔中有對驗證消息InvalidUpdateAttempt的引用。 當記錄被嘗試更新但它不存在時產生。 我還沒有找到任何方法來抑制它的觸發器,它看起來像沒有,也許你會有更多的運氣。