具有预加载关系的 Laravel 模型

Posted

技术标签:

【中文标题】具有预加载关系的 Laravel 模型【英文标题】:Laravel model with preloaded relation 【发布时间】:2021-07-19 02:38:32 【问题描述】:

我有一个数据库表来存储我的职位,以免重复它们,并且 Job 模型在内部具有关系,所以当我使用 Eloquent 模型时,我必须总是一遍又一遍地调用或加载 JobTitles 模型。有没有办法始终使用内部预加载 JobTitles 的 Job Model?

    class Job extends Model
    
        use Notifiable;

        protected $fillable = [ ... ];

        protected $hidden = [
        'token',
        ];


    
        public function title()
        
            return $this->belongsTo('App\Models\JobTitle','job_title_id');
        

        public function people()
        
            return $this->belongsToMany('App\Models\Person','job_person','job_id','person_id');
        
        
    

这是 JobTitle 模型

class JobTitle extends Model

    use Notifiable;

    protected $table = "job_titles";

    protected $primaryKey = 'job_title_id';

    protected $fillable = [
        'name',
    ];

    protected $hidden = [
    'token',
    ];


    public function jobs()
    
        return $this->hasMany('App\Models\Job','job_title_id');
    

    

现在我在控制器中的代码如下所示:

 $job = Job::all()->load('title');

它工作正常,但是当我从人们那里调用工作时

 $personJobs = Person::find(1)->jobs()->load('title')->get();

报错,有什么办法吗?

【问题讨论】:

不是'title'而不是'title'吗? @codeninja 是的,我刚刚纠正了它,但这不是问题 【参考方案1】:

当通过 $person->jobs() 方法调用关系时,您最终会得到一个查询构建器,因此您不能调用像 load() 这样的模型方法,因为您没有模型的实例。

在获得第一个结果之前调用关系会更有效 (nested eager loading)

$person = Person::with('jobs.title')->find(1);
$personJobs = $person->jobs;

如果您不想从数据库中查询人员数据,您应该使用 whereHas

$personJobs = Job::whereHas('people', function($personQueryBuilder) 
    $personQueryBuilder->where('id',1);
)->with('title')->get();

【讨论】:

【参考方案2】:

load() 在查询执行后执行。这称为延迟加载。急切加载使用with()

急切加载通常比延迟加载快(我可能在这个上错了,如果我错了,请纠正我)。

此外,使用jobs() 或任何其他关系,这将返回关系对象本身,而通过->Jobs 访问它将执行关系查询并返回一个集合(如果有的话)或模型(如果有的话)。

$personJobs = Person::find(1)->jobs()->load('title')->get(); 不起作用的原因是因为您本质上是在说“工作 hasMany 关系将加载不起作用的“标题”,因为hasMany 没有load() 功能。

所以如果你想解决这个问题,你可以做Person::with('jobs.title')->find(1)Person::find(1)->load('jobs.title')

【讨论】:

Person::with('jobs.title')->find(1) 也给了我个人数据 @HydyrAvezberdiyew 在这种情况下,使用$personsJobs = Person::find(1)->Jobs->load('title'); 但是你建议使用 with(),不是吗? @杰里米 @HydyrAvezberdiyew 问题可以通过加载或使用来解决,只是知道使用哪个以及在哪里使用它。 @HydyrAvezberdiyew 个人,我尽量使用 with() 。我通常在条件上使用 load()。如果在任何情况下都会对整个函数使用某些东西,那么我使用 with()【参考方案3】:

始终使用内部预加载 JobTitles 的作业模型。你可以在你的工作模型中添加$with 属性:

class Job extends Model

   use Notifiable;
   
   protected $with = ['title'];


【讨论】:

是的,我也使用过 $with,在官方文档中找到。但是忘了回答我的问题谢谢。

以上是关于具有预加载关系的 Laravel 模型的主要内容,如果未能解决你的问题,请参考以下文章

从第一个表中选择特定列,在 Laravel 中进行预加载

如何从 Laravel 上的预加载中获取嵌套数据?

Laravel 使用自定义查询预加载嵌套关系

三十PHP框架Laravel学习笔记——模型的预加载

预加载具有多对多关系的核心数据的最佳实践

Gorm 预加载及实现联表条件查询仿WhereHas