Laravel在关系对象上的位置


79

我正在使用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 ...
}

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

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


2
有什么例外?
丹尼·科平

Answers:



66

@Cermbo的答案与此问题无关。在他们的回答,Laravel会给大家Events如果每个Event都有'participants'IdUser1

但是,如果你想获得的所有Events的所有'participants'规定,所有'participants'有一个IdUser1,那么你应该做这样的事情:

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

注意:

where使用你的表名,而不是型号名称。


17
为了帮助读者理解:与其他答案不同,无论参与者的用户ID是否为1,这都将返回ALL Events,但如果返回,则仅包括参与者对象。
Chuck Le Butt

6

对于多个联接,请使用类似以下代码的内容:

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

$ someId值是什么?
Fernando Torres

@FernandoTorres$someId 是另一个变量,您不能直接在此函数内使用,因此您需要传入use(...方法。
Muhammad Shahzad


1

我在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

0

[OOT]

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

这是一个示例,如果您想显示所有参与者都满足特定要求的事件。假设所有参与者都已全额付款。因此,它将不会返回有一个或多个参与者未完全付款的事件。

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

假设状态完全未支付[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])
Akbar Noto
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.