Laravel - whereHas() 中关系的最新记录

Posted

技术标签:

【中文标题】Laravel - whereHas() 中关系的最新记录【英文标题】:Laravel - latest record from relationship in whereHas() 【发布时间】:2016-07-29 16:55:27 【问题描述】:

这是我在这里的第一篇文章,所以请原谅任何错误:)

我目前正在从事库存管理应用程序(Laravel)的项目。我到了我所做的任何事情都不起作用的地步,所以现在我请求帮助。

我有一张产品表,其中一些与其他产品有关系。一切都发生在一张桌子上。如果产品有子级,则子级会覆盖父级。

products table view

然后,我对它们运行的​​所有查询都使用以下逻辑:

如果该项目没有任何子项,请使用它。 如果项目有子项,请使用最新的子项(最高 id)

现在我在模型文件中创建了关系:

public function childItems()
    return $this->hasMany('\App\OrderItem','parent_id');


public function parentItem()
    return $this->belongsTo('\App\OrderItem','parent_id');


public function latestChild()
    return $this->hasOne('\App\OrderItem','parent_id')->orderBy('id','desc')->limit(1);

latestChild() 关系的问题在于,当您运行此查询时:

\App\OrderItem::find(7)->latestChild()->get()

它工作正常并且只返回一个(最新的)(id 6)关系记录 - 为此我必须添加 orderBy 和限制到 hasOne()。

但是当我想在作用域中使用这种关系时,在 whereHas 方法中,它不能正常工作,因为它需要任何孩子而不是最新的。

public function scopeDue($query)
    return $query->where(function($q)
                            $q->has('childItems','==',0)->has('parentItem','==',0)->whereDate('due_date','=', Carbon::today()->toDateString())->whereNull('return_date');
                        )->orWhere(function($q2)
                            $q2->has('childItems')->has('parentItem','==',0)->whereHas('childItems',function($q3) use($q2)
                                $q3->whereDate('due_date','=', Carbon::today()->toDateString())->whereNull('return_date');
                            );
                        )->with('latestChild');


但是,with() 在最后返回正确的记录。

我认为,它之所以如此有效,是因为我的关系 latestChild() 返回所有子项(尽管有 hasOne()),并且当我在 whereHas 中使用它时,它忽略了我应用的过滤功能。

我知道我的描述有点复杂,但为了更好地解释它,我将使用一个示例。在修补程序中执行以下操作

\App\OrderItem::due()->get();

应该只返回记录 id 2,因为数字 7 有孩子,当然 id 5 是到期的,但最新的孩子是 id 6,没有到期。

我希望我已经对它进行了足够的解释,以便让您帮助我,因为我已经为此发疯了。 如果您对如何通过更改现有的或更改其整体逻辑来实现我的需求有任何想法,请提供帮助!

谢谢, 达雷克

【问题讨论】:

您好!我遇到了同样的问题,无法通过 ONLY 最后一个相关的模型过滤模型...你能解决这个问题吗?谢谢。 @Zalo 有一种稍微不同的做法,就是在父模型上使用一个子选择列来选择最新的孩子的id,然后可以用来加入对应的孩子。我之前确实回答了一个非常相似的问题here。 【参考方案1】:

试试这个:

->with(
    [
        'latestChild' => function (HasOne $query) 
            return $query->latest('id')->limit(1);
        
    ]
);

【讨论】:

【参考方案2】:

我认为问题出在您的latestChild() 方法中,您在该方法中执行了limit(1)。为什么不试试last() 方法呢?

所以:

public function latestChild()
    return $this->hasOne('\App\OrderItem','parent_id')->last();

编辑:

这样返回值怎么样:

public function latestChild()
    $item = App\OrderItem::all()->last();
    return $item;

【讨论】:

感谢您的回复!不幸的是,last() 不能在 Builder 上使用。我接受它,它只能用于数组。 这个怎么样? ^ 这个不返回关系,而是从整个表中返回最后一个OrderItem(与特定对象无关)。 我明白了,你能附上整个数据库关系模型吗? 另外我不知道has() 方法是否有 == 符号,因为 SQL 没有?

以上是关于Laravel - whereHas() 中关系的最新记录的主要内容,如果未能解决你的问题,请参考以下文章

从 Laravel 5.1 升级到 Laravel 5.8 后 whereHas() 变慢

在 Laravel 5 中合并 'with' 和 'whereHas'

Laravel - whereHas 查询没有返回正确的记录

Laravel - 使用“whereHas”获取嵌套关系

Laravel 的 whereHas 表现不佳

Laravel:具有 whereHas 和多对多关系的全局范围