使用したリレーショナルクエリ単一のデータベーステーブルからデータを選択するためにARを使う方法を見てきました。この章では、いくつかの関係するデータベーステーブルをつなげ、結合されたデータセットに書き戻す方法を示します。リレーショナルARを使うためには、主外部キー関係が結合すべきテーブル間で正しく定義されている必要があります。ARはこれらのリレーションに関してどのようにテーブルを結合するかを決定するために、メタデータに依ります。1.0.1版からはデータベースに外部キー制約が定義されていない場合でもリレーショナルARを使用することができます。簡単のため、この章では例題として、以下のエンティティ関係(ER)図に示されるデータベーススキーマを使用します。外部キー制約のサポートはDBMS毎に異ります。SQLiteは外部キーをサポートしませんが、テーブルを作成する際に制約を宣言します。ARはリレーショナルなクエリを正しくサポートするためにこの制約宣言を利用します。MySQLはInnoDBエンジンの場合には外部キーをサポートしますが、MyISAMの場合はしません。従って、MySQLデータベースの場合にはInnoDBの使用を推奨します。MyISAMの場合には、以下のようなトリックを使用してリレーショナルなクエリを実行することができます。Foo(id)');上記では説明したリレーションを認識させるため、ARから読めるように外部キー制約を記述するCOMMENTキーワードを使用します。¶ARのリレーショナルクエリを使用する前に、ARに対して他のARクラスとどのように関係しているかを知らせる必要があります。2つのARクラスのリレーションは、ARクラスによって表現されるデータベーステーブルのリレーションと直接関係しています。データベースの観点からは、2つのテーブルAとBの関係には、3つのタイプがあります。1対多(例えばUserとPost)、1対1(例えばUserとProfile)、多対多(例えばCategoryとPost)。ARでは、以下の4種類のリレーションがあります。PostはUserに属す)。Userは多くのPostを持つ)。Userはたかだか1つのProfileを持つ)。これはデータベースにおいて多対多の関係と対応します。多対多の関係を1対多の関係に分割するために、関連したテーブルが必要です。大部分のDBMSは、直接多対多の関係をサポートしないためです。例題のデータベーススキーマでは、PostCategoryはこの目的のために使用されます。AR用語では、BELONGS_TOとHAS_MANYの組合せとして、MANY_MANYを説明することができます。Postは多くのCategoryに属しています。Categoryには多くのPostがあります。ARでのリレーション宣言は、CActiveRecordクラスのrelations()メソッドをオーbライドすることで行います。このメソッドはリレーション構成の配列を返します。各々の配列要素は以下のフォーマットで示す一つのリレーションを意味します。...付加オプション)ここでVarNameはリレーションの名前です。RelationTypeはリレーションのタイプを指定します。それは4つの定数、self::BELONGS_TO、self::HAS_ONE、self::HAS_MANY、self::MANY_MANYのうちの1つです。ClassNameはこのARクラスに関連したARクラスの名前です。ForeignKeyはリレーションに関係する外部キーを指定します。付加オプションは各々のリレーション(後述)の終わりに指定すことができます。以下のコードでどのようにUserとPostクラスのリレーションを宣言するかを示します。外部キーは2個以上の列で構成される複合キーでもかまいません。この場合は名前は外部キー名の結合となるべきであり、スペースまたはカンマで分割されます。MANY_MANYのリレーションにおいては、関連したテーブル名は、外部キーでも指定されなければなりません。categoryID)により指定されます。ARクラスのリレーションの宣言は、各々のリレーションのために暗黙のうちにプロパティをクラスに加えます。リレーショナルなクエリが実行された後、対応するプロパティは関連するARインスタンスで満されます。¶リレーショナルクエリを実行する最も単純な方法は、ARインスタンスのリレーショナルなプロパティを読み出すことです。プロパティが以前にアクセスされていない場合には、リレーショナルクエリは初期化されます。そのクエリは2つの関係するテーブルを結合し、現行のARインスタンスの主キーでフィルタリングされます。これはレイジーローディングアプローチとして知られており、リレーショナルなクエリは関連するオブジェクトが最初にアクセスされるときに実行されます。以下の例は実際にこのアプローチをどのように使用するかを示します。対応するプロパティはナルまたは空の配列となります。BELONGS_TOとHAS_ONEリレーションの場合結果はナルです。HAS_MANYとMANY_MANYでは空の配列です。どんなプロパティにアクセスする前にも、結果を通してループする必要があることに注意してください。non-object(非オブジェクトのプロパティを取得しようとしている)」エラーが発生します。レイジーローディングアプローチは使うのに非常に便利ですが、それはいくつかの場合に効率的ではありません。N個の著者情報にアクセスする場合、レイジーローディングアプローチを使うとN個のジョインクエリを発行しなければなりません。この状況ではいわゆるイーガーローディングアプローチをとる必要があります。イーガーローディングアプローチでは、主なARインスタンスと共に関連するARインスタンスを取得します。with()メソッドを用いることで達成されます。$posts=Post::model()->with('author')->findAll();上記のコードはPostインスタンスの配列を返します。関連したUserインスタンスにより格納されています。イーガーローディングアプローチでは一度で全ての情報を取得できます。以下のコードにより、著者とカテゴリーをポストと共に戻します。$posts=Post::model()->with('author','categories')->findAll();我々は、イーガーローディングを入れ子で実行することもできます。リレーション名のリストする代わりに、以下のようにリレーション名の階層的な表現をwith()メソッドに渡します。'categories')->findAll();上記の例は、著者とカテゴリーと共にすべての投稿を取得します。各々の著者のプロフィールと投稿を戻します。with()の使用法はバージョン1.0.2から変わりました。対応するAPIドキュメンテーションを注意深く読んでください。YiiのAR実装は非常に効率的です。必要とする結果を得るためにN+1個のSQLクエリを必要とします。従って、先程の例ではpostsとcategoriesのプロパティを取得するため、3つのSQLクエリを実行する必要があることを意味します。他のフレームワークは、1つのSQLクエリだけを用いたより急進的なアプローチをとっています。見には急進的なアプローチはより効率的にみえます。いうのはより少ないクエリがDBMSによって解析され実行されるのためです。そのアプローチは実際には2つの理由から非実用的です。第1に結果の中に多くの反復的なデータコラムがあり、それを送信し処理する余分な時間がかかるためです。第2に結果セットの列の数は関係するテーブルの数で指数的に増大します。リレーションがより複雑になるにつれ、管理不可能になります。バージョン1.0.2から、1つのSQLクエリだけでリレーショナルなクエリを実施することもできます。together()呼び出しをwith()の後に追加するだけです。'categories')->together()->findAll();上記のクエリは1つのSQLクエリで実行されます。User、Postテーブルをジョインするクエリの2つのSQLクエリを必要とします。¶さらなるオプションがリレーション宣言において指定されることができることを述べました。これらのオプションは、名前-値のペアとして指定されますが、リレーションの質問をカスタマイズするのに用いられます。それらは以下の通りまとめられます。リレーションのあるARクラスのために選ばれるコラムのリスト。デフォルトは'*'でありすべてのコラムを意味します。nameCountのような)に現れるならば、aliasTokenを使って曖昧さをなくされなければなりません。デフォルトは空で無条件を意味します。注意:コラム参照はaliasTokenを用いてて曖昧さをなくされなければなりません(例えば??.id=10)。生成されたSQL文に縛らるパラメータ。これは名前-値のペアの配列として与えられなければなりません。このオプションはバージョン1.0.3から利用できるようになりました。ここで指定される条件は、ANDオペレーターを使用しJOIN条件に追加されます。コラム参照はaliasTokenを使って曖昧さをなくす必要があることに注意すべきです(例えば??.id=10)。このオプションはバージョン1.0.2から利用できるようになりました。デフォルトでは空で無条件を意味します。子供のリレーションを持つオブジェクトのリストであり、このオブジェクトと共にロードすべきオブジェクトです。このオプションを不適切に使用すると、無限リレーションループが形成される可能性がありますので、注意してください。コラム接頭辞の場所取りです。コラム参照の曖昧さをなくすために対応するテーブル別名と置き換えられます。デフォルトでは'??.'です。このリレーションと結びついたテーブルの別名です。このオプションはバージョン1.0.1から利用できるようになりました。デフォルトはナルであり、テーブル別名が自動的に生成されることを意味します。これは以下の点からaliasTokenと異なります。aliasTokenは単なる場所取りであり、実際のテーブル別名と置き換えられるためです。テーブルがこのリレーションと結びついたかどうかは、主テーブルと共にジョインとして強制されなければなりません。このオプションはHAS_MANYとMANY_MANY関係のときのみ意味があります。このオプションがセットされないか偽である場合、HAS_MANYまたはMANY_MANYリレーションはパフォーマンスを向上させるためにのJOIN文を持ちます。このオプションはバージョン1.0.3から利用できるようになりました。