Doctrine2でSQLを発行する際のカラムのエイリアス変更
久しぶりのブログ更新です。
はい、忙しさにかまけて更新をさぼっていました。すみません。
今回は、Symfony2+Doctrineで開発を行っていた際に困った現象と回避方法をについて
Doctrine2ではDQLやQueryBuilderを使用してSQLを発行するとカラム名+連番のエイリアスをつけて発行します。
例) id , name, tel, faxの4つのカラムを持つperson テーブルの場合
SELECT * FROM person; ↓ DQLで発行すると SELECT p0_.id AS id0, p0_.name AS name1, p0_.tel AS tel2, p0_.fax AS fax3 FROM person AS p0_;
通常はこれで被ることはないだろうという設計なのでしょうが、たまたまこの連番の部分が被ってしまいSQLの結果がおかしくなるケースが発生。
※ ちなみにDoctrine1の場合は、「テーブルエイリアス名+アンダーバー2個+カラム名 」となっています。
今更テーブル構造の見直しを行うのも無理なので、エイリアスの文字列を作成する部分をカスタマイズすることに。
エイリアス名を整形しているクラスは以下。
Doctrine\ORM\Mapping\DefaultQuoteStrategy
ちなみに、Doctrineのconfigクラスから上記クラスを再設定できるようになっているのですが、Symfony2側からはconfigクラスが隠ぺいされてどうしようもなかったのでEntityManagerも独自クラスに変更することに。
1. まずは、DefaultQuoteStrategyを継承したクラスを作成し、getColumnAliasをoverride。
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class KzlQuoteStrategy extends DefaultQuoteStrategy
{
/**
* {@inheritdoc}
*/
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
{
// Trim the column alias to the maximum identifier length of the platform.
// If the alias is to long, characters are cut off from the beginning.
// And strip non alphanumeric characters
// 後ろに連番をつけるだけでは、カラム名がかぶってしまうので間にアンダーバー入れる。
//$columnName = $columnName . $counter;
$columnName = $columnName . "__". $counter;
$columnName = substr($columnName, -$platform->getMaxIdentifierLength());
$columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName);
return $platform->getSQLResultCasing($columnName);
}
}2. 次に、EntityManagerを継承したクラスを作成し、QuoteStrategyで使用するクラスを変更。
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
use Doctrine\Common\EventManager;
class KzlEntityManager extends EntityManager
{
/**
*
* {@inheritdoc}
*/
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
// カラム名のエイリアスを変更するために以下設定を上書き
$config->setQuoteStrategy(new KzlQuoteStrategy());
return parent::create($conn, $config, $eventManager);
}
}3. 後は、上記EntityMamagerを使用するようにSymfony2の設定を変更します。
app/config/config.ymlに以下を追加
parameters:
# EntityManagerを入れ替え
doctrine.orm.entity_manager.class: ネームスペース\KzlEntityManagerこれでめでたくエイリアスが被るケースを回避できました。