この記事は、 Symfony Advent Calendar 2015 14日目の記事です。
Doctrineのドキュメント第27章 Best Practices の翻訳。ライセンスは、MIT。
ベストプラクティス
ここで言及されている、データベース設計に影響するベストプラクティスは、おおむね、Doctrineを使用するときのベストプラクティスであり、一般的なデータベース設計のベストプラクティスを反映しているとは限らない。
関係を可能な限り制限する
可能な限り関係を制限するのは重要だ。これが意味するのは:
- 探索する方向を制限する(可能なら双方向の関係を使わない)
- 本質的でない関係を除去する
ということだ。これにはいくつかの利点がある:
- ドメインモデルの結合を減らす
- ドメインモデルのコードがシンプルになる(双方向性を適切に保つ必要がない)
- Doctrineのための作業が少なくなる
複合キーを使わない
Doctrineは複合キーを完全にサポートしているが、それでも、可能な限り使わないのがベストだ。複合キーは、Doctrineによる追加の仕事を要求するし、それゆえ、エラーの可能性がより高くなる。
イベントを慎重に使う
Doctrineのイベントシステムは、すばらしいし、速い。イベント(とくに、ライフサイクルイベント)の使い過ぎが、アプリケーションに悪い影響をもたらすとしてもだ。それゆえ、イベントは慎重に使うべきだ。
カスケードを慎重に使う
persist/remove/merge等の自動的なカスケードは、とても便利だが、賢く使われるべきだ。単純にすべての関連にすべてのカスケードを追加したりしないこと。どのカスケードが特定の関連にとって実際に意味があり、それがいかにも使われそうなシナリオはあるのか、考えること。
特殊文字を使わない
クラス、フィールド、テーブルあるいはカラム名には、いかなる非ASCII文字も使わないこと。Doctrineそのものは、多くの箇所でUnicode安全ではないし、PHPそのものがUnicode対応になるまで、そうはならないだろう。
識別子のクオートを使わない
識別子のクオートは、予約語を使うためのワークアラウンドだ。予約語を使うことは、エッジケースでしばしば問題を起こす。識別子のクオートを使わないこと、そして、テーブルまたはカラム名に予約語を使わないこと。
コンストラクタ内でコレクションを初期化する
コンストラクタ内で、任意のビジネスコレクションを初期化するのが、推奨されるベストプラクティスだ。例:
<?php
namespace MyProject\Model;
use Doctrine\Common\Collections\ArrayCollection;
class User {
private $addresses;
private $articles;
public function __construct() {
$this->addresses = new ArrayCollection;
$this->articles = new ArrayCollection;
}
}
エンティティのフィールドに外部キーをマップしない
外部キーは、オブジェクトモデルにおいて、なんの意味も持たない。外部キーは、リレーショナルデータベースが、どのようにして関係を確立するか、というものだ。オブジェクトモデルは、オブジェクトの参照を通じて関係を確立する。それゆえ、外部キーをオブジェクトフィールドにマッピングすることは、オブジェクトモデルにリレーショナルモデルの詳細を大胆に漏らしてしまう。こういうことはすべきではない。
明示的にトランザクションを分離する
Doctrineが、flush()時に、すべてのDML1操作を自動的にトランザクションで囲む一方で、自分で明示的にトランザクション境界を設定することは、ベストプラクティスであると考えられている。さもなくば、どの単一のクエリも、小さなトランザクションで囲まれることになる(そう、SELECTクエリもだ)。そうすれば、トランザクションを越えてデータベースと対話することがなくなるためだ。読み取りのみの(SELECT)クエリのための、こういった小さなトランザクションは、一般に目立ったパフォーマンス上のインパクトをもたらさない一方、より少ない数の、よく練られたトランザクションを使うのが、やはり好ましい。つまり、明示的なトランザクション境界によって確立されるトランザクションだ。
- (訳注)Data Manipulation Language ↩