【问题标题】:Laravel's Eloquent ORM versus Query BuilderLaravel 雄辩的 ORM 与查询构建器
【发布时间】:2015-03-15 20:14:19
【问题描述】:

我有 2 张桌子:usersarticlesusers 表有一个名为is_suspended 的列,它接受yesnoarticles 表有一个名为is_published 的列,它接受01。要从数据库中获取文章数据,articles.is_published 必须等于 1 并且 users.is_suspended 必须等于 no。现在假设users.is_suspended 等于yes,如果我尝试使用这样的查询生成器获取文章的数据:

// first code:

    $articles = Article::join('users', 'articles.user_id', '=', 'users.user_id')
        ->select(['articles.*', 'users.user_name', 'users.user_email'])
        ->where('articles.article_id', '=', 9)
        ->where('articles.is_published', '=', 1)
        ->where('users.is_suspended', '=', 'no')
        ->get();

这将完美运行并且不会返回任何内容(因为users.is_suspended = yes)。现在让我们尝试使用 Laravel Eloquent ORM 获取同一篇文章,如下所示:

// second code:

$articles = Article::with([
    'user' => function($query) {
        $query->select(['user_id', 'user_name', 'user_email'])
            ->where('users.is_suspended', '=', 'no');
    }])
    ->where('articles.article_id', '=', 9)
    ->where('articles.is_published', '=', 1)
    ->get();

在这种情况下,我会得到下一个结果:

[
  {
    article_id: 9,
    user_id: 1,
    article_title: "Article title here",
    article_body: "Article body here",
    is_published: 1,
    created_at: "2015-01-17 02:26:24",
    updated_at: "2015-01-17 02:26:24",
    user: null
  }
]

即使用户被挂起,它也会获取文章的数据,这是错误的。所以我的问题是如何修复第二个代码以像第一个代码一样工作?

【问题讨论】:

    标签: php mysql laravel orm eloquent


    【解决方案1】:

    您可能希望使用with 来确保您延迟加载关系,但您对其施加的任何限制仅适用于加载的关系。要限制对未暂停用户的文章的响应,您需要使用whereHas 方法。

    $articles = Article::with(['user' => function($q){
            $q->select(['user_id', 'user_name', 'user_email', 'created_at']);
        }])
        ->whereHas('user', function($q) {
            $q->where('is_suspended', '=', 'no');
        })
        ->where('articles.article_id', '=', 9)
        ->where('articles.is_published', '=', 1)
        ->get();
    

    【讨论】:

    • 那太好了。但是我如何选择特定的列以及我应该把它放在哪里:select(['user_id', 'user_name', 'user_email'])。我试图这样说: $q->select(['user_id', 'user_name', 'user_email', 'created_at'])->where('is_suspended', '=', 'no');但它会导致错误说:(基数违规:1241 操作数应包含 4 列)。
    • 为你添加了它,你把它放在你原来拥有它的地方,在with方法回调中。
    • 它会导致错误说:explode() 期望参数 2 是字符串,给定对象。
    • 我的错误,我没有将 with 参数包装在一个数组中。更改以使其正常工作。
    【解决方案2】:

    正如@DavidBarker 所说,您需要whereHas 而不是with(或两者都需要,但在这种情况下不需要with)。

    但我建议更多,请考虑此代码的可读性:

    $article = Article::whereHas('user', function ($q) {
       $q->active();
    })->published()->find(9);
    

    它使用scopes

    因此,您可以采取以下措施让您的生活更轻松:

    1. is_suspended 更改为bool,因为:

      $user->is_suspended; // no
      (bool) $user->is_suspended; // true    
      
    2. User 模型上定义范围suspended 和在Article 上定义published

      // Article model - on User accordingly
      public function scopePublished($query)
      {
          $query->where('is_published', 1);
      }
      
    3. 当你想获取单个模型时,使用find($id)where('col', $id)->first() 而不是get,因为后者会返回一个集合,即使只有一个结果。

    【讨论】:

      猜你喜欢
      • 2019-12-09
      • 1970-01-01
      • 2020-02-07
      • 1970-01-01
      • 2016-02-26
      • 2021-05-31
      • 2019-09-14
      • 1970-01-01
      • 2018-02-13
      相关资源
      最近更新 更多