【问题标题】:Laravel - whereHas checking latest record of a relationship without checking othersLaravel - whereHas 检查最新的关系记录而不检查其他人
【发布时间】:2018-11-02 08:30:48
【问题描述】:

我有两个具有一对多关系的表。

预订 - (id)

booking_tasks - (id, booking_id,user_id)

一个预订有很多任务 一任务一预约

预订模式:

 public function tasks() {
    return $this->hasMany('App\BookingTask');    
  }

BookingTask 模型

public function booking() {
    return $this->belongsTo('App\Booking');
} 

我想获取预订列表, user_id = 2 表示最新的预订任务。我不想检查其他旧的预订任务。

例如:

我想检查 booking_task 的 user_id=2 的最后一条记录是否作为预订。 在示例中最后一个 booking_task 的 user_id = 5。所以它不会作为预订。

我的代码是:

$bookings=Booking::whereHas('tasks',function($q){
            $q->where('user_id',2);//this will check whether any of record has user_id =2
})->get();

我也用过这个: 但这不是正确的,

$bookings=Booking::whereHas('tasks',function($q){
                $q->latest()->where('user_id',2)->limit(1);//this will check whether any of record has user_id =2 and return latest one.
    })->get();

我能解决这个问题吗,我也必须使用 Laravel Eloquent。

【问题讨论】:

  • 您找到解决方案了吗?
  • @user9500574 我可以使用“Jonas Staudenmeir”的答案找到一种方法来完成任务,
  • 我用了他的解决方案,效果很好,非常感谢

标签: php sql-server laravel-5 eloquent


【解决方案1】:

这需要更复杂的查询:

$bookings = Booking::select('bookings.*')
    ->join('booking_tasks', 'bookings.id', 'booking_tasks.booking_id')
    ->where('booking_tasks.user_id', 2)
    ->where('booking_tasks.id', function($query) {
        $query->select('id')
            ->from('booking_tasks')
            ->whereColumn('booking_id', 'bookings.id')
            ->latest()
            ->limit(1);
    })->get();

【讨论】:

  • 完美运行
  • 谢谢。效果很好。我正在使用 whereHas() 对很多人来说太慢了。
【解决方案2】:

我发现 Jonas 的答案有效,但因为它是一个带有连接的查询,它会导致模型中急切加载关系的问题。因此,我将该解决方案与whereHas 函数一起使用,提出了一个可用于作用域的解决方案,因此可以重复使用。

第一步涉及在AppServiceProvider 中的查询Builder 中添加一个宏。

use Illuminate\Database\Query\Builder;

Builder::macro('whereLatestRelation', function ($table, $parentRelatedColumn) 
{
    return $this->where($table . '.id', function ($sub) use ($table, $parentRelatedColumn) {
        $sub->select('id')
            ->from($table . ' AS other')
            ->whereColumn('other.' . $parentRelatedColumn, $table . '.' . $parentRelatedColumn)
            ->latest()
            ->take(1);
    });
});

这基本上使 Jonas 答案的子查询部分更加通用,允许您指定连接表和它们连接的列。它假定另一列是“id”列,因此可以进一步改进。要使用它,您可以这样做:

$userId = 2;
Booking::whereHas('tasks', function ($tasks) use ($userId) {
    $tasks->where('user_id', $userId)
        ->whereLatestRelation((new Task)->getTable(), 'booking_id');
});

这与接受的答案的逻辑相同,但更容易重复使用。然而,它会慢一点,但这应该值得重用。

【讨论】:

    【解决方案3】:

    这个

    我想获取预订列表,user_id = 2 表示最新的预订任务。我不想检查预订的其他旧 booking_tasks。

    没有多大意义,但我认为你想要的是所有 user_id == 2 的预订,其中至少有 1 个任务和 每次预订的最新任务?那么也许这会起作用?

    Booking::where('user_id', 2)->with('tasks', function($query){
        $query->orderBy('created_at', 'DESC')->take(1);
    })->has('tasks')->get();
    

    【讨论】:

      【解决方案4】:

      你试过 ->first() 结合逆序 orderBy() 吗?

      like $q->where('user_id','=','2')->orderBy('id','DESC')->first();

      【讨论】:

        猜你喜欢
        • 2022-01-03
        • 1970-01-01
        • 2016-07-29
        • 2022-08-19
        • 1970-01-01
        • 2017-11-18
        • 2021-05-25
        • 2015-06-24
        • 1970-01-01
        相关资源
        最近更新 更多