在 Phinx 中重置 INSERT queryBuilder 以供重用
Reset INSERT queryBuilder for re-use, in Phinx
我在使用 Phinx(版本 0.10.8)时遇到了一个特殊的问题:我必须迁移一个 table 以便插入一个 table,然后 AUTO_INCREMENTed last-insert-ID 插入另一个table.
因为我在一个 for 循环中,所以我只想继续为第一个 table 中的插入循环使用相同的 insert-query-builder;而不是重建整个插入构建器。但是我不知道如何重置 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
似乎有一个 public 重置方法。但我不确定如何访问该 ValueBinder。
This thread suggests to use closures, which is actually a good idea now that I think about it. They were mentioned in passing in this doc。但它是如何工作的?我傻了。
// 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();
重复使用 queris 可能很棘手,我不确定是否真的建议这样做。无论如何,默认情况下 values are being added,而不是 replaced,这允许轻松地动态构建多行插入查询,所以这就是你的问题。
如果要替换值,则需要访问基础 \Cake\Database\Expression\ValuesExpression
object, which can be obtained via the query builder's clause()
method。虽然您可以使用 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();
我在使用 Phinx(版本 0.10.8)时遇到了一个特殊的问题:我必须迁移一个 table 以便插入一个 table,然后 AUTO_INCREMENTed last-insert-ID 插入另一个table.
因为我在一个 for 循环中,所以我只想继续为第一个 table 中的插入循环使用相同的 insert-query-builder;而不是重建整个插入构建器。但是我不知道如何重置 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
似乎有一个 public 重置方法。但我不确定如何访问该 ValueBinder。
This thread suggests to use closures, which is actually a good idea now that I think about it. They were mentioned in passing in this doc。但它是如何工作的?我傻了。
// 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();
重复使用 queris 可能很棘手,我不确定是否真的建议这样做。无论如何,默认情况下 values are being added,而不是 replaced,这允许轻松地动态构建多行插入查询,所以这就是你的问题。
如果要替换值,则需要访问基础 \Cake\Database\Expression\ValuesExpression
object, which can be obtained via the query builder's clause()
method。虽然您可以使用 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();