LoginSignup
24
13

More than 5 years have passed since last update.

LaravelでDB上はhasManyだけど1件だけ取りたいときはhasOneを使うといい

Last updated at Posted at 2017-10-26

どういうことか

Userが複数のPostを持っていて、その最新の1件だけ表示したいとき、公式ドキュメントに従うと

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}

とhasManyリレーションを定義して

$user->posts()->orderBy('created_at', 'desc')->first();

と書くのが一般的だと思いますが、最新の1件しか要らないことが予め分かっている場合

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function latestPost()
    {
        return $this->hasOne('App\Post')
            ->orderBy('created_at', 'desc');
    }
}

とhasOneで定義して

$user->latestPost;

と書くこともできます。

ほんとうか

HasManyクラスのソースHasOneクラスのソースを見ると、hasManyでは

Illuminate/Database/Eloquent/Relations/HasMany.php
public function getResults()
{
    return $this->query->get();
}

となっているのに対し、hasOneでは

Illuminate/Database/Eloquent/Relations/HasOne.php
public function getResults()
{
    return $this->query->first() ?: $this->getDefaultFor($this->parent);
}

としているだけですので、Query Builderの使い方としても正しいと言えます。

どうやって使い分けるか

今回のPostsの例でいうと、いずれにせよ一覧表示などを作ると思いますので、hasManyを定義したほうがいいです。
実際の業務で「有効期間内の最新のキャンペーンのみ適用したい」という場面があり、明らかに1件しか使わないのにDB上は古いキャンペーンが残ってしまうので、そのような場合hasOneで定義した方が有効だと思いました。

24
13
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
24
13