0

我在使用 Phinx(版本 0.10.8)时遇到了一个特殊问题:我必须迁移一个表,以便将该行插入到一个表中,然后将 AUTO_INCREMENTed last-insert-ID 插入到另一个表中。

由于我处于 for 循环中,因此我只想继续为第一个表中的插入回收相同的插入查询构建器;而不是重建整个插入构建器。但我不知道如何重置VALUES数据。

一个例子来说明这个问题:

// insert-builder I hope to re-use.
$builder = $this->getQueryBuilder()->insert(array(
    'note',
))->into('test_table');

// cache this empty state for reset attempt #2.
$empty = $builder;

// insert one row of values.
$builder->values(array(
    'note' => "Please don't copy me. Please don't copy me. Please don't copy me ...",
))->execute();

// dump info.
var_dump($this->getAdapter()->getConnection()->lastInsertId());
$rows = $this->fetchAll("SELECT COUNT(*) FROM test_table");
var_dump($rows);

// reset attempts.    
//$builder->getValueBinder()->reset();              // (1)
$builder = $empty;                                  // (2)
//$builder->getQuery()->getValueBinder()->reset();  // (3)

// insert second row.
$builder->values(array(
    'note' => "Second insert.",
))->execute();

// dump info.
var_dump($this->getAdapter()->getConnection()->lastInsertId());
$rows = $this->fetchAll("SELECT COUNT(*) FROM test_table");
var_dump($rows);

数字 (3) 给了我一个例外,并且 (1) 和 (2) 给了我相同的输出,即在 2 次插入后我有 3 行:

string(1) "1"
array(1) {
  [0]=>
  array(2) {
    ["COUNT(*)"]=>
    string(1) "1"
    [0]=>
    string(1) "1"
  }
}
string(1) "2"
array(1) {
  [0]=>
  array(2) {
    ["COUNT(*)"]=>
    string(1) "3"
    [0]=>
    string(1) "3"
  }
}

反正我是在黑暗中钓鱼。我真的找不到任何好的文档。

/vendor/cakephp/database/ValueBinder.php似乎确实有一个公共重置方法。但我不确定如何到达那个 ValueBinder。


这个线程建议使用闭包,现在我考虑一下这实际上是一个好主意。在本文档中顺便提到了它们。但它是如何工作的?我哑了。

// not like this.
$values = array(
    'note' => "Please don't copy me. Please don't copy me. Please don't copy me ...",
);
$this->execute(function() use ($builder, $values) {
    return $builder->values($values)->execute();
});

// not like this.
$this->execute(function($builder) use ($values) {
    return $builder->values($values)->sql();
});

// not like this.
$builder->values(function($builder) use ($values) {
    return $builder->values($values);
})->execute();
4

1 回答 1

1

重用查询可能很棘手,我不确定是否真的建议这样做。无论如何,默认情况下添加而不是替换值,这允许轻松动态地构建多行插入查询,所以这是你的问题。

如果要替换值,则需要访问底层\Cake\Database\Expression\ValuesExpression对象,该对象可以通过查询构建器的clause()方法获得。虽然您可以使用ValuesExpression::setValues()新值覆盖现有值(这需要是一个嵌套数组,因为此方法接受多行数据),但这样做不会使查询对象回到脏状态,也不会清除值绑定器,因此您最好的选择可能是使用ValuesExpression::setValues()重置数据,然后使用查询构建器values()方法设置新数据,例如:

$stmt = $builder
    ->values([
        'note' => 'first note'
    ])
    ->execute();
// ...
$stmt->closeCursor();

// reset the values clause
$builder
    ->clause('values')
    ->setValues([]);

// define new values, this will put the query in a dirty state and reset the value binder
$stmt = $builder
    ->values([
        'note' => 'second note'
    ])
    ->execute();
// ...
$stmt->closeCursor();
于 2019-07-29T10:38:16.343 回答