【问题标题】:Laravel where on relationship objectLaravel 在关系对象上的位置
【发布时间】:2015-07-11 11:08:59
【问题描述】:

我正在使用 Laravel 5.0 开发一个 Web API,但我不确定我正在尝试构建的特定查询。

我的课如下:

class Event extends Model {

    protected $table = 'events';
    public $timestamps = false;

    public function participants()
    {
        return $this->hasMany('App\Participant', 'IDEvent', 'ID');
    }

    public function owner()
    {
        return $this->hasOne('App\User', 'ID', 'IDOwner');
    }
}

class Participant extends Model {

    protected $table = 'participants';
    public $timestamps = false;

    public function user()
    {
        return $this->belongTo('App\User', 'IDUser', 'ID');
    }

    public function event()
    {
        return $this->belongTo('App\Event', 'IDEvent', 'ID');
    }
}

现在,我想获取特定参与者的所有事件。 我试过了:

Event::with('participants')->where('IDUser', 1)->get();

where 条件应用于Event 而不是Participants。以下给了我一个例外:

Participant::where('IDUser', 1)->event()->get();

我知道我可以这样写:

$list = Participant::where('IDUser', 1)->get();
for($item in $list) {
   $event = $item->event;
   // ... other code ...
}

但是向服务器发送这么多查询似乎效率不高。

使用 Laravel 5 和 Eloquent 通过模型关系执行 where 的最佳方法是什么?

【问题讨论】:

  • 异常情况是什么?

标签: php laravel eloquent relationship where-clause


【解决方案1】:

对关系执行此操作的正确语法是:

Event::whereHas('participants', function ($query) {
    return $query->where('IDUser', '=', 1);
})->get();

这将返回参与者的用户 ID 为 1 的事件。如果参与者的用户 ID 不是 1,则不会返回事件。

阅读更多https://laravel.com/docs/5.8/eloquent-relationships#eager-loading

【讨论】:

  • 为了帮助读者理解:这将返回参与者的用户 ID 为 1 的事件。如果参与者的用户 ID 不是 1,则不会返回事件。
  • 真的很抱歉。我只是混淆并在错误的线程中发送评论
  • @ChuckLeButt 您的评论应在此答案中进行编辑。您的评论很有价值。
【解决方案2】:

@Cermbo 的回答与这个问题无关。在那个答案中,Laravel 将给你所有Events 如果每个Event'participants'IdUser1

但如果你想得到所有Events 和所有'participants',前提是所有'participants'IdUser 为1,那么你应该这样做:

Event::with(["participants" => function($q){
    $q->where('participants.IdUser', '=', 1);
}])

注:

where 中使用您的表名,而不是模型名。

【讨论】:

  • 为了帮助读者理解:与其他答案不同,这将返回所有事件,无论参与者的用户 ID 是否为 1,但仅包含参与者对象。
【解决方案3】:

适用于 laravel 8.57+

Event::whereRelation('participants', 'IDUser', '=', 1)->get();

【讨论】:

  • 这里是原始的pull request,如果有人需要了解它是如何工作的。
  • 角质。超级的东西。也可以这样工作:php Event::whereRelation('participants', 'IDUser', 1)->get();
【解决方案4】:

如果有多个连接,请使用如下代码:

$userId = 44;
Event::with(["owner", "participants" => function($q) use($userId ){
    $q->where('participants.IdUser', '=', 1);
    //$q->where('some other field', $userId );
}])

【讨论】:

  • $someId 值应该是多少?
  • @FernandoTorres $someId 是另一个变量,您不能直接在此函数中使用它,因此您需要传入 use(... 方法。
【解决方案5】:

使用此代码:

return Deal::with(["redeem" => function($q){
    $q->where('user_id', '=', 1);
}])->get();

【讨论】:

    【解决方案6】:

    对于 laravel 8,请改用这个

    Event::whereHas('participants', function ($query) {
         $query->where('user_id', '=', 1);
    })->get();
    

    这将返回只有用户 ID 为 1 的参与者具有该事件关系的事件,

    【讨论】:

      【解决方案7】:

      我在 BaseModel 中创建了一个自定义查询范围(我的所有模型都扩展了这个类):

      /**
       * Add a relationship exists condition (BelongsTo).
       *
       * @param  Builder        $query
       * @param  string|Model   $relation   Relation string name or you can try pass directly model and method will try guess relationship
       * @param  mixed          $modelOrKey
       * @return Builder|static
       */
      public function scopeWhereHasRelated(Builder $query, $relation, $modelOrKey = null)
      {
          if ($relation instanceof Model && $modelOrKey === null) {
              $modelOrKey = $relation;
              $relation   = Str::camel(class_basename($relation));
          }
      
          return $query->whereHas($relation, static function (Builder $query) use ($modelOrKey) {
              return $query->whereKey($modelOrKey instanceof Model ? $modelOrKey->getKey() : $modelOrKey);
          });
      }
      

      您可以在许多情况下使用它,例如:

      Event::whereHasRelated('participants', 1)->isNotEmpty(); // where has participant with id = 1 
      

      此外,您可以尝试省略关系名称并仅传递模型:

      $participant = Participant::find(1);
      Event::whereHasRelated($participant)->first(); // guess relationship based on class name and get id from model instance
      

      【讨论】:

        【解决方案8】:

        [OOT]

        有点 OOT,但这个问题是与我的问题最接近的话题。

        如果您想显示 ALL 参与者满足特定要求的事件,这是一个示例。比方说,所有参与者都全额支付的事件。因此,它不会返回有一个或多个参与者未全额支付的事件。

        只需使用其他2个状态的whereDoesntHave即可。

        假设状态是根本没有支付 [eq:1]、支付了一部分 [eq:2] 和全额支付 [eq:3]

        Event::whereDoesntHave('participants', function ($query) {
           return $query->whereRaw('payment = 1 or payment = 2');
        })->get();
        

        在 Laravel 5.8 - 7.x 上测试

        【讨论】:

        • 我喜欢这个的地方是,你仍然可以获得Event::with(['participants, avenue])等关系对象
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-25
        • 2014-01-01
        • 2018-11-27
        • 2021-12-14
        • 2016-04-26
        相关资源
        最近更新 更多