https://blog.fagai.net/2013/09/08/laravel-eloquent-orm-primary-key
こちらの記事ですが、以下の記事の内容を行うと、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つなのかもしれませんね・・。しかしながらスキーマビルダーは複合主キーが定義出来る・・・なんだろうこの矛盾
 
                    
コメントを残す
コメントを投稿するにはログインしてください。