Laravel Eloquent 表之间通过其他表的关系

Posted

技术标签:

【中文标题】Laravel Eloquent 表之间通过其他表的关系【英文标题】:Laravel Eloquent Relationship of tables through other tables in between 【发布时间】:2021-03-26 14:12:40 【问题描述】:

在 Laravel 中,我在 LevelOne、LevelTwo、LevelThree 和 LevelFour 的 4 个模型之间有以下关系:

//LevelOne Model
   public function levelTwo()
       return $this->hasMany(LevelTwo::class);
   
//LevelTwo Model
    public function levelOne()
        return $this->belongsTo(LevelOne::class);
    

    public function levelThree()
        return $this->hasMany(LevelThree::class);
    
//LevelThree Model
    public function levelTwo()
        return $this->belongsTo(LevelTwo::class);
    
    
    public function levelFour()
        return $this->hasOne(LevelFour::class);
    

//LevelFour Model
    public function levelThree()
        return $this->belongsto(LevelThree::class);
    

我的目标是使用一个控制器,对于这个例子,文件称之为 JoinController ,并返回一个这样的字符串

[
    "id": 1,
    "name": "Entry 1 at level one",
    "levelTwo": [
        
        "id": 1,
        "levelone_id": 1,
        "name": "Entry 1 on level two",
        "levelThree": [
            
            "id": 1,
            "leveltwo_id": 1,
            "name": "Entry x on level three",
            "levelFour": [
                
                "id": 1,
                "levelthree_id": 1,
                "name": "Entry x on level four"
                ,
                
                "id": 2,
                "levelthree_id": 1,
                "name": "Entry x on level four"
                
            ]
            ,
            
            "id": 2,
            "leveltwo_id": 1,
            "name": "Entry x on level three",
            "levelFour": [
                
                "id": 3,
                "levelthree_id": 2,
                "name": "Entry x on level four"
                ,
                
                "id": 4,
                "levelthree_id": 2,
                "name": "Entry x on level four"
                
            ]
            
        ]
        ,
        
        "id": 2,
        "levelone_id": 1,
        "name": "Entry 2 on level two",
        "levelThree": [
            
            "id": 3,
            "leveltwo_id": 2,
            "name": "Entry x on level three",
            "levelFour": [
                
                "id": 5,
                "levelthree_id": 3,
                "name": "Entry x on level four"
                ,
                
                "id": 6,
                "levelthree_id": 3,
                "name": "Entry x on level four"
                
            ]
            ,
            
            "id": 4,
            "leveltwo_id": 2,
            "name": "Entry x on level three",
            "levelFour": [
                
                "id": 7,
                "levelthree_id": 4,
                "name": "Entry x on level four"
                ,
                
                "id": 8,
                "levelthree_id": 4,
                "name": "Entry x on level four"
                
            ]
            
        ]
        
    ]
,

    //.... same as previous, n times
]

到目前为止,我能够从 JoinController 成功返回“下一级”的信息:

public function getAllLevels()
  return LevelOne::with('levelTwo')->get();

但是,当我尝试向下一层时,它会失败,如下所示:

public function getAllLevels()
  return LevelOne::with('levelTwo')->with('levelThree')->get();

错误是:调用模型 [App\Models\LevelOne] 上的未定义关系 [levelThree]。

但是,如果我返回以下内容:

return LevelTwo::with('levelOne')->with('levelThree')->get();

这适用于一种关系“向上”和一种关系“向下”,但如果我添加 LevelFour 它将不起作用。 (是的,我在控制器顶部正确导入模型:使用 \App\Models\LevelOne; 使用 \App\Models\LevelTwo; ...等)

在普通的 SQL 中,我只需要编写一个查询来连接外键以获得所需的结果。在 Eloquent 中,当 LevelOne 模型不通过任何 ID 而是通过中间的其他模型表连接时,我不确定如何使 LevelOne 模型与 LevelFour 建立关系,例如级联连接。请指出正确的方向。

注意:像我之前展示的那样返回一个字符串(json)对我来说非常重要,我需要返回LevelOne的所有值,显示它在LevelTwo的关系中的所有行等等等等“ n" 次(在我的例子中是 4 次)。

【问题讨论】:

【参考方案1】:

您可能需要更改 LevelThree 中的关系

//LevelThree Model
    public function levelTwo()
        return $this->belongsTo(LevelTwo::class);
    
    
    public function levelFour()
        return $this->hasOne(LevelFour::class);
    

然后你可以形成一个查询

public function getAllLevels()

    return LevelOne::with('levelTwo.levelThree.levelFour')->get();

【讨论】:

我的原始代码与您建议更改LevelThree的关系正确,我在这里写错了。我已经用正确的代码编辑了这个问题。使用 with('levelTwo.levelThree.levelFour') 的查询非常简单,但我无法在文档中找到它。非常感谢!【参考方案2】:

有几件事你可以看看。 首先,对于不是 2 而是 3 层之间的关系,尝试寻找 hasManyThrough。这样你就可以直接从 levelOne 到 levelThree,根本不需要调用 levelTwo。同样的方法,但是你可能需要尝试

如你所说 错误是:调用模型 [App\Models\LevelOne] 上的未定义关系 [levelThree]。

这是因为在调用 with() 时,您仍然对 LevelOne 执行此操作,而不是 LevelTwo。 LevelOne::with('levelTwo') 不会返回 LevelTwo,而是返回一个 LevelOne,它具有该名称下的 LevelTwo 的实例/实例,因此您可以访问它 $levelOne->levelTwo。如果你想调用'withs'来遍历返回的实例,你需要写一个逗号和下一个关系的名称,就像这样。

LevelOne::with('levelTwo.levelThree.levelFour')->get();

【讨论】:

以上是关于Laravel Eloquent 表之间通过其他表的关系的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent 在与其他表连接后从关系中选择字段

一个模型和多个模型之间的 Laravel Eloquent 关系作为 MorphOne?

Laravel Eloquent - 查询数据透视表

如何通过 laravel eloquent 模型 Laravel 5 加入三个表

Laravel Eloquent - 使用连接选择列文本类似于其他表中的列文本

Laravel Eloquent ORM "whereHas" 通过表