Laravel hasManyThrough 等价物:通过另一个模型的 belongsTo 关系

Posted

技术标签:

【中文标题】Laravel hasManyThrough 等价物:通过另一个模型的 belongsTo 关系【英文标题】:Laravel hasManyThrough equivalent: belongsTo relationship through another model 【发布时间】:2014-06-15 11:08:43 【问题描述】:

我有一个模型,它属于另一个模型,那个模型属于第三个模型,我想要一个雄辩的方法来将第一个模型与第三个模型联系起来。

不过,似乎没有 belongsToThrough(或 hasOneThrough)方法。我已经尝试过链接多个belongsTo 方法,但没有奏效(Call to undefined method Illuminate\Database\Query\Builder::belongsTo())。有什么想法吗?

以下是模型示例:

// The first model
// Schema: this model has a middle_id column in the database
class Origin extends Eloquent 
    public function middle()
    
        return $this->belongsTo('Middle');
    


// The second model
// Schema: this model has a target_id column in the database, but NOT an origin_id column
class Middle extends Eloquent 
    public function target()
    
        return $this->belongsTo('Target');
    


// The third model
class Target extends Eloquent 

我想做的是向Origin 模型添加类似以下方法的内容:

// A relationship method on the first "origin" model
public function target()

    // First argument is the target model, second argument is the middle "through" model, third argument is the database column in middle model that it uses to find the target model, or soemthing
    return $this->hasOneThrough('Target', 'Middle', 'target_id');

这样我就可以使用$originInstance->target->title

【问题讨论】:

你试过hasManyThrough吗? 我没有,我只是假设这是许多关系。让我试试,谢谢! HasOne 和 HasMany 都扩展了抽象的 HasOneOrMany,它们非常相似。我很确定它对你有用,但是它可能会返回一个 Collection 而不是单个模型,这可能是我现在能想到的唯一缺点。 啊,不,很遗憾,这行不通。这是因为我的源表属于中间表,中间表属于目标表,而中间表不属于源表,这是hasManyThrough要求的。让我澄清一下这个问题。 好的,那就不行了。目前没有这种方式通过关系的方法,只有A -> hasOneOrMany -> B -> hasOneOrMany C的另一种方式。但是您仍然可以使用点嵌套关系,例如 origin->middle->target->title (如果到处都是 hasOne) 【参考方案1】:
public function target()  
    $middle = $this->belongsTo('Middle', 'middle_id'); 
    return $middle->getResults()->belongsTo('Target'); 

更新:

从 laravel 5.8 开始,您可以使用hasOneThrough 关系:

public function target()  
    return $this->hasOneThrough('Target', 'Middle');

【讨论】:

谢谢,感谢您的回答!我可能没有足够清楚地表达我的问题,但我的问题是我需要直接访问目标作为与原点的关系。由于目前已设置,我可以使用$origin->middle->target 访问目标,因为每个都属于下一个。但是,这对我不起作用,因为我需要跳过中间人。我希望这能解决我的问题。 我想了解更多关于“getResults()”的信息,我正在阅读这个答案比它发布的时间晚了 2 年,通过简单的谷歌搜索,看起来 getResults() 被替换为得到()。仍然需要确认这一点,但我希望它可以帮助其他人在 2017 年看到这个! AFAIK 这个答案仍然有效,我仔细检查了每个Relation 类和getResults() 没有被删除(例如HasMany Relation L5.4),你测试答案了吗?跨度> 不幸的是,这不支持预加载:( @CharlesWood Laravel 添加了一个支持急切加载的函数hasOneThrough,我已经更新了我的旧答案,谢谢。【参考方案2】:

如果这是消息在瓶子里,并且瓶子归用户所有user > bottle > message

我知道获取关系对象的唯一方法是:

// THIS IS IN App\Message

public function bottle()

    return $this->belongsTo('App\Bottle');


public function user()

    return $this->bottle->belongsTo('App\User');

【讨论】:

它有效。但它有效率吗?这是否会为每条消息的每一瓶创建一个单独的查询,而不是只为用户的整个请求运行一个查询。 @JasmeetSingh,当然它会创建单独的查询,但它使编码时的生活更轻松。考虑到对象缓存是当今应用程序中的标准配置,我不介意。如果您不使用这些东西,您将不得不在易于编码和应用程​​序速度之间跳舞。对具有连接的用户的整个请求进行一次查询会快得多,但它在应用程序中的可重用性并不高。我们希望将数据库层与应用程序分开,因此代码中没有原始 SQL 查询,也没有 @JasmeetSingh 或者你可以使用Eager Loading【参考方案3】:

您可以使用hasOneThrough,但您需要自定义键。

public function parent()

    return $this->hasOneThrough(Parent::class, Middle::class, 'id', 'id', 'middle_id', 'parent_id');

Origin 属于 Middle,Middle 属于 Parent。 Middle需要有parent_id外键,Origin有middle_id外键。

终于可以使用了:

Origin::find(1)->parent;

【讨论】:

天哪!我知道“谢谢”cmets 是不鼓励的,但非常感谢!在我尝试了所有其他令人费解的事情之后,我简直不敢相信这能奏效! 乐于助人 ;)【参考方案4】:
// First Model
public function secondModelRelation()

    return $this->belongsTo('App\Models\SecondModel');


public function thirdModelRelation()

    // Call the thirdModelRelation method found in the Second Model
    return $this->secondModelRelation->thirdModelRelation;



// Second Model
public function thirdModelRelation()

    return $this->belongsTo('App\Models\ThirdModel');



// Third Model

【讨论】:

以上是关于Laravel hasManyThrough 等价物:通过另一个模型的 belongsTo 关系的主要内容,如果未能解决你的问题,请参考以下文章

通过 Laravel 关系查询 HasManyThrough 检索相关记录

Laravel:如何平均嵌套 hasMany 关系(hasManyThrough)

Laravel 5 hasManyThrough 数据透视表

Laravel hasManyThrough 深入

Laravel 5 hasManyThrough 重复行内容

Laravel Eloquent: hasManyThrough 多对多关系