首页 > 解决方案 > Laravel:如何对 wherehas 的第一个结果执行 where 子句(order by)

问题描述

在新的一年里,我对 Eloquent 有一个问题:

我有一个EtabInvariant模型,它与 EtabVariant 模型有这样的关系 orderBy):

class EtabInvariant extends Model
{   
   
    // I've deleted this part because it's a big table...

    public function etab_variant()
    {
        return $this->hasMany(EtabVariant::class, 'ev_fk_ei_uai_nombre')->orderBy('ev_debut_annee_scolaire','desc');
    }
}

在我的控制器中,我想对etab_variant的第一个结果执行 where 子句。

以下代码有效,但 where 子句适用于etab_variant的每个结果。

class VisiteController extends Controller
{
    public function index(Request $request)
    {
       $q = EtabInvariant::with(['etab_variant']);
       $nbClasses = 13; // This is an input property in the real app
       $q->whereHas('etab_variant', function($query) use ($nbClasses) {
         $query->where('ev_nb_classes', $nbClasses);
       });
       return response()->json($q->get(), 200);
    {
}

我只想在 whereHas 的第一个结果上应用 where 子句(因为 etab_variant 是 orderBy 并且只有第一个结果让我感兴趣)所以,我尝试了很多东西,但没有任何效果。

// This doesn't work
// I guess it's because find() return a collection or something like that...
$query->first()->where('ev_nb_classes', $nbClasses);

如果有人能帮助我,那将是圣诞节的奇迹!谢谢大家,新年快乐!

弗洛朗


编辑(在@lagbox 回答之后)

如果我使用hasMany关系,我的控制器的结果是这样的(我已经删除了所有多余的信息):

[
    {
        "ei_uai_nombre": 140545,
        "etab_variant": [
        {
            "ev_debut_annee_scolaire": 2020,
            "ev_fk_ei_uai_nombre": 140545,
            "ev_nb_classes": 10
        },
        {
            "ev_debut_annee_scolaire": 2019,
            "ev_fk_ei_uai_nombre": 140545,
            "ev_nb_classes": 8
        }]
    },
    {
        "ei_uai_nombre": 140691,
        "etab_variant": [
        {
            "ev_debut_annee_scolaire": 2020,
            "ev_fk_ei_uai_nombre": 140691,
            "ev_nb_classes": 5
        },
        {
            "ev_debut_annee_scolaire": 2019,
            "ev_fk_ei_uai_nombre": 140691,
            "ev_nb_classes": 7
        }]
    }
]

如果我使用hasOne关系,正如@lagbox 在答案中所建议的那样,代码如下:

    public function etab_variant_latest()
    {
        // Seul le résultat le plus récent sera renvoyé
        return $this->hasOne(EtabVariant::class, 'ev_fk_ei_uai_nombre')->orderBy('ev_debut_annee_scolaire','desc');
    }

我的控制器的结果是这样的:

[{“ei_uai_nombre”:140545,“etab_variant_latest”:{“ev_debut_annee_scolaire”:2020,“ev_fk_ei_uai_nombre”:140545,“ev_nb_classes”:10}},{“ei_uai_nombre”:140691,“etab_debut_variant_latest”:{“ev_debut_variant_latest”:{“ev_debut_variant_latest” ,“ev_fk_ei_uai_nombre”:140691,“ev_nb_classes”:5 } }]

所以,它几乎可以工作:控制器为每一行返回最新的“etab_variant”。问题是 where 子句适用于每个结果中的所有“etab_variant”。例如,如果 where 子句为 'ev_nb_classes>6',则结果与上述相同(ev_nb_classes 值在 2020 年为 5,但在 2019 年为 7)。

我想只在最新的 etab_variant 上应用 where 子句(在上面的例子中是 2020 年)

我不知道我是否清楚...如果您需要其他说明,请随时告诉我。

标签: laraveleloquent

解决方案


您可以尝试创建另一个关系,它是HasOne您的HasMany关系版本:

public function etab_variant()
{
    return $this->hasOne(EtabVariant::class, ...)->orderBy(...);
}

// the current relationship renamed to plural since it is a has many
public function etab_variants()
{
    return $this->hasMany(EtabVariant::class, ...)->orderBy(...);
}

然后你可以使用你所拥有的,因为你所拥有的使用etab_variant现在是HasOne.

EtabInvariant::with('etab_variants')->whereHas('etab_variant', ...)...

推荐阅读