40
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Laravel】リレーション先のデータ取得方法を調べた

Posted at

LaravelのEloquent ORMは、テーブル間のリレーションを管理・操作する際の独自の表現があります。
Laravel5.8 Eloquent:リレーション

"1対多"や"多対多"のリレーションなどはよく使うのではないでしょうか。
今回は、これらのリレーションを定義したのち、実際にリレーション先のテーブルのデータをどうやって取得するのか、いくつか手法を調べました。

※ここから先は、予めモデルクラスに以下のリレーションを定義したという前提で進めます。
ブログサイトなどで、1人のユーザーが複数の投稿を登録しているという想定です。

User.php
    public function posts()
    {
        return $this->hasMany('App\Posts');
    }

1.メソッドで呼び出す

マニュアルに記載されている、基本のやり方です。

User.php
// ユーザーに紐づく投稿を全て取得し、Collectionで返す
    public function getPosts()
    {
        return $this
            ->find(1)
            ->posts()
            ->get();
    }

// 条件を付け加えることももちろん可能
// ユーザーに紐づく投稿について、題名で部分一致検索するものをCollectionで返す
    public function getPostByTitle()
    {
        return $this
            ->find(1)
            ->posts()
            ->where('title', 'LIKE', '%hoge%')
            ->get();
    }

posts メソッドが呼び出されると、システムは Posts モデルクラスを参照します。
ですから、通常のモデルクラスの操作と同じように、メソッドチェーンであらゆる条件などを追加できます。

公式マニュアル曰く

Eloquentは「動的プロパティ」を提供しているので、モデルのプロパティとして定義したリレーションメソッドへアクセスできる

ということで、以下の書き方も可能です

User.php
    public function getPosts()
    {
        return $this
            ->find(1)
            ->posts; //プロパティで呼び出す
    }

さて、筆者も初めはこの方法で全てなんとかなると思っていましたが…ちょっとした落とし穴がありました。
というのも、上記のメソッドで取得できるのは特定のユーザーに紐づく、投稿のデータのみであるため、例えばユーザーのデータと投稿のデータを同時に返したいという場合や、ある条件を満たすユーザーに紐づく投稿を取得するといった場合に不都合が生じたのです。

User.php
    public function findPostByUserIsOver25yo()
    {
        return $this
            ->where('age', '>', '25')
            ->get()
            ->posts;
            //get()した時点でcollectionオブジェクトになっており、collectionからpostsプロパティを呼び出そうとしているため、エラーになる
    }

そのような時はどうすればよいのでしょうか?

2.withメソッドを用いる

このような場合は、 with() メソッドを使うとうまくいくようです。
参考にさせていただきました

(公式マニュアルよく読んだらひっそりと使われていた…調べて存在を知るまで気がつかなかった)

User.php
    public function findPostByUserIsOver25yo()
    {
        return $this
            ->with('posts')
            ->where('age', '>', '25')
            ->get();
    }

このように取得すると、 各 User モデルクラスの relations プロパティに Post モデルクラスが紐づいた状態になり、条件に合うユーザーのユーザー情報と投稿データを一度に取得できます。

まとめ

両者を比較した上で、筆者の意見としては全部withでよくね?というのが正直なところです。
特に親テーブルのデータが不要で小テーブルの情報だけ取得したいという場合は、メソッドで呼び出すのがいいのだと思いますが、結局 relations プロパティで呼び出せるしなぁ…
もう少し色々な挙動を試してみたいです。

ご意見・ご指摘などありましたらコメントお寄せください。

40
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?