注意:Laravel4の話です
2013-09-19追記
こちらの記事ですが、以下の記事の内容を行うと、insert等ができなくなるようになってしまいました・・・。
どうやら最後のIDが取得出来ないからこうなってしまうようです。
互換性などの点からもIDは付けるようにしましょう。複合ユニークキーとインデックスをつければそれなりにちゃんと速くなるはず
こんにちは。ファガイです。
先日から個人的にサイトを制作していたのですが、衝撃の事実がわかりまして・・・
Eloquent ORMは複合主キーに対応していない!
うん、複合主キーに対応していない。
皆見たらわかると思うんだ、Illuminate\Database\Eloquent\Builderのfindメソッドを見てみよう。
public function find($id, $columns = array('*'))
{
$this->query->where($this->model->getKeyName(), '=', $id);
return $this->first($columns);
}
あとは、Illuminate\Database\Eloquent\Modelとかも。
public static function find($id, $columns = array('*'))
{
$instance = new static;
if (is_array($id))
{
return $instance->newQuery()->whereIn($instance->getKeyName(), $id)->get($columns);
}
return $instance->newQuery()->find($id, $columns);
}
そもそも、primaryKeyは1つであると確定しているのも問題じゃないのかと思ってる。
リレーションを組もうとしたが、この仕様だと、primaryKeyは1つでなければいけない。複合主キーで組もうと思ったらリレーションが組めない。
結構大問題だった。
大問題でも無かった。Query Builderで取ってきてくっつければ普通に取得できた。
Eloquent Modelのfindメソッドの動き的にid複数を取得して来れる的な仕様と見れる。だがQuery Builderには実装されていない。まだ粗はありそう。
対処方法
上記で出したメソッドにidがarrayで来たとかprimaryKeyがarrayだったとか判定が必要。
あと、コアとなっているEloquent\Relations\BelongsTo等のaddConstrationsをいじる必要がある。
これを修正しないと、リレーションを組むことが出来ませんでした。
自分の場合はこのような形に変更しています。例えば、BelongsToの場合。
public function addConstraints()
{
if (static::$constraints)
{
$key = $this->related->getKeyName();
$table = $this->related->getTable();
$count = count($key);
if($count > 1) {
for($i = 0; $i < $count; ++$i) {
$this->query->where($table.'.'.$key[$i], '=', $this->parent->{$this->foreignKey[$i]});
}
}else{
$this->query->where($table.'.'.$key, '=', $this->parent->{$this->foreignKey});
}
}
}
コアとなっている部分をいじってしまっているので、composer updateをやってしまうともう一度直さなきゃいけなさそうですね。
Eloquent Modelの方は一つBaseEloquentとかモデルを用意して、それを継承させる形にすればよいでしょう。
ではではー。
2013-09-08追記
複合主キーは拡張性が無くなったり、変更に強くないため主キーが1つなのかもしれませんね・・。しかしながらスキーマビルダーは複合主キーが定義出来る・・・なんだろうこの矛盾
コメント
こんにちは。
理由は簡単です。Laravelのデータベース操作はEloquent ORMだけではないからです。クエリービルダーで操作することもできるからです。
基本的に、スキーマーは、その他の通り、テーブルのスキーマーを(完全ではないが)簡単に定義するだけのものです。Eloquentとの整合性を考えているのではなく、サポートしているDBエンジン間の違いを埋め、できるだけ共通に定義できるようにするためのものです。(とはいっても、MySQL専用とか、ありますが。)
こんにちは。コメントありがとうございます。
Query Builderを使うことで改変せずに情報を取得し、データに含めることが出来ました。
また、複合キーをリレーションで組む事自体にも色々と問題があるようですね。取得方法に差異が出てきますが、今後は複合で取る際にはクエリービルダーを使用することにします。
本当に私も最初は悩みました。けど、それほどシリアスなシステムを作成しているわけでないので、初めからid主キー一本だけと、割りきって使い出し、それから便利に使っています。(というより、SQLはもう直接書きたくなくなりました。)
まあ、Eloquentを使い始める時は、誰でも通る道でしょうね。
通りすがりです。
自分は複合keyを使う時はYii、それ以外はLaravelで使い分けます。
PHP縛りの場合のみですが。。