INSERT
オプションを使用してドクトリンクエリを作成するにはどうすればよいON DUPLICATE KEY UPDATE
ですか?
9 に答える
Symfony 2の 場合、生の SQL を使用します。
$em->getConnection()->prepare("INSERT INTO table SET
some_fields = "some data", created_at = NOW()
ON DUPLICATE KEY UPDATE
some_fields = "some data", updated_at = NOW()
")->execute();
問題は、これが MySQL 固有の問題であるため、Doctrine で直接カバーされないことです。
コメントが述べたように、これには RawSQL クエリを作成する必要があります。これが最も簡単な方法です。
より洗練された真の DB 独立性が必要な場合は、Eventsとその可能性を調べてください。実際のクエリが実行される前に、存在を確認し、存在する場合はそれに応じて行動することができます。
ORM/PHP に依存しない方法は、データベース側でこの問題を処理するストアド プロシージャ/トリガーを作成することです。
私は同じ問題を抱えていましたが、少し調査したところ、Doctrine ではそれができないようです。私の解決策は、挿入の前にfindByを実行して、一意のフィールドを持つレコードが存在するかどうかを確認することでした。これがエンティティを返す場合、永続化する新しいエンティティを作成する代わりに、そのエンティティを更新して永続化します。
すべての挿入の前に選択を行っているため、パフォーマンスが心配な場合、これは理想的ではありません。ただし、Doctrine はデータベースに依存しないため、MySQL にロックする唯一の代替手段です。これはトレードオフの 1 つです。つまり、パフォーマンスと移植性のどちらが必要かということです。
次のような関数を使用して、生のSQLを構築および実行できます。
/**
*
* insertWithDuplicate('table_name', array('unique_field_name' => 'field_value', 'field_name' => 'field_value'), array('field_name' => 'field_value'))
*
* @param string $tableName
* @param array $insertData
* @param array $updateData
*
* @return bolean
*/
public function insertWithDuplicate($tableName, $insertData, $updateData) {
$columnPart = '';
$valuePart = '';
$columnAndValue = '';
foreach ($insertData as $key => $value) {
$value = str_replace(array('"', "'"), array('\"', "\'"), $value);
$columnPart .= "`" . $key . "`" . ',';
is_numeric($value) ? $valuePart .= $value . ',' : $valuePart .= "'" . $value . "'" . ',';
}
foreach ($updateData as $key => $value) {
$value = str_replace(array('"', "'"), array('\"', "\'"), $value);
is_numeric($value) ? $columnAndValue .= $key . ' = ' . $value . ',' : $columnAndValue .= "`" . $key . "`" . ' = ' . "'" . $value . "'" . ',';
}
$_columnPart = substr($columnPart, 0, strlen($columnPart) - 1);
$_valuePart = substr($valuePart, 0, strlen($valuePart) - 1);
$_columnAndValue = substr($columnAndValue, 0, strlen($columnAndValue) - 1);
$query = "INSERT INTO " . $tableName .
" (" . $_columnPart . ") "
. "VALUES" .
" (" . $_valuePart . ") "
. "ON DUPLICATE KEY UPDATE " .
$_columnAndValue;
return $this->entityManager->getConnection()
->prepare($query)->execute();
}
これが役立つ場合は、クエリ ビルダーを拡張して任意の SQL を追加できます (明らかに、これは PDO エンジン間では機能しない可能性があります)。
class MyQB extends QueryBuilder {
private $append = '';
/**
* {@inheritdoc}
*/
public function getSQL() {
return parent::getSQL() . $this->append;
}
/**
* Append raw SQL to the output query
*
* @param string $sql SQL to append. E.g. "ON DUPLICATE ..."
*
* @return self
*/
public function appendSql($sql) {
$this->append = $sql;
return $this;
}
}