【问题标题】:Laravel Relationship availability after save()save() 后的 Laravel 关系可用性
【发布时间】:2017-01-24 00:12:55
【问题描述】:

我正在使用 Laravel 5 构建一个简单的时间跟踪应用程序,其中我有两个 Laravel 模型,一个称为“用户”,一个称为“周”

关系非常简单:
周.php:

public function user()
{
    return $this->belongsTo('App\User');
}

用户.php:

function weeks()
{
    return $this->hasMany('App\Week');
}

现在,User.php 文件还有一个名为“getCurrentWeek()”的简单辅助/新奇函数,顾名思义,它返回当前星期

function getCurrentWeek()
{
    $possibleWeek = $this->weeks->sortByDesc('starts')->all();
    if(count($possibleWeek) != 0)
    {
        return $possibleWeek[0];
    }
    else
    {
        return null;
    }
}

我的问题是:如果我为用户创建第一周并将其附加/关联到用户,如下所示:

$week = new Week;

//Omitted: Setting so attributes here ...

$week->user_id = $user->id;
$weeks->save()
$user->weeks()->save($week);

然后调用$user->getCurrentWeek();方法,该方法返回null,虽然已经创建了新的一周,但与用户相关并已保存到数据库中。在我看来,getCurrentWeek() 的预期行为是返回新创建的一周。
我在这里对 Eloquent 有什么误解/做错了什么?

【问题讨论】:

    标签: php laravel model eloquent relationship


    【解决方案1】:

    不需要$user->weeks()->save($week);,因为您使用$week->user_id = $user->id; 手动将星期附加到用户并保存它。

    您实际上可以将整个函数重写为:

    function getCurrentWeek()
    {
        return $this->weeks->sortByDesc('starts')->first();
    }
    

    或者

    function getCurrentWeek()
    {
        return $this->weeks()->orderBy('starts', 'desc')->first();
    }
    

    编辑:

    我做了一点概念证明,它像这样工作得很好:

    应用\用户.php

    function weeks()
    {
        return $this->hasMany('App\Week');
    }
    
    function getCurrentWeek()
    {
        return $this->weeks->sortByDesc('starts')->first();
    }
    

    应用\Week.php

    public function user()
    {
        return $this->belongsTo('App\User');
    }
    

    routes/web.php 或 App/Http/routes.php

    Route::get('poc', function () {
        $user = App\User::find(1);
        $week = new App\Week;
        $week->user_id = $user->id;
        $week->starts = Carbon\Carbon::now();
        $week->save();
        return $user->getCurrentWeek();
    });
    

    结果:

    {
        id: 1,
        user_id: "1",
        starts: "2016-09-15 21:42:19",
        created_at: "2016-09-15 21:42:19",
        updated_at: "2016-09-15 21:42:19"
    }
    

    【讨论】:

    • $user->getCurrentWeek() 在我上面的代码中直接在$user->weeks()->save($week); 之后被调用。我尝试了您的方法,但现在出现错误。 BadMethodCallException in Builder.php line 2405: Call to undefined method Illuminate\Database\Query\Builder::all()。错误恰好发生在更改的行上。我在这里到底做错了什么?我复制并粘贴了您的确切代码。
    • 嗨@SvenE。我做了一点概念证明,你的方式和我的方式都很好。我附上了所有代码,以便您可以将其与您的代码进行比较。查看我的编辑。
    • 尝试使用 get() 而不是 all()
    • 非常感谢@Björn,你的 poc-code 帮我调试了问题 :)
    【解决方案2】:

    关系属性在第一次被访问时被延迟加载。加载后,它们不会使用从关系中添加或删除的记录自动刷新。

    由于您的 getCurrentWeek() 函数使用了关系属性,因此此代码将起作用:

    $week = new Week;
    // setup week ...
    $user->weeks()->save($week);
    
    // $user->weeks attribute has not been accessed yet, so it will be loaded
    // by the first access inside the getCurrentWeek method
    dd($user->getCurrentWeek());
    

    但是,这段代码不起作用:

    // accessing $user->weeks lazy loads the relationship
    echo count($user->weeks);
    
    // relate a new record
    $week = new Week;
    // setup week ...
    $user->weeks()->save($week);
    
    // $user->weeks inside the method will not contain the newly related record,
    // as it has already been lazy loaded from the access above.
    dd($user->getCurrentWeek());
    

    您可以修改 getCurrentWeek() 方法以使用关系方法 ($this->weeks()) 而不是属性 ($this->weeks),这将始终命中数据库,或者您可以重新加载关系(使用 @987654327 @method) 添加或删除记录后。

    getCurrentWeek()方法更改为使用关系方法weeks()(@Bjorn提供的更新方法)

    function getCurrentWeek()
    {
        return $this->weeks()->orderBy('starts', 'desc')->first();
    }
    

    或者,使用load() 方法刷新关系:

    // accessing $user->weeks lazy loads the relationship
    echo count($user->weeks);
    
    // relate a new record
    $week = new Week;
    // setup week ...
    $user->weeks()->save($week);
    
    // reload the weeks relationship attribute
    $user->load('weeks');
    
    // this will now work since $user->weeks was reloaded by the load() method
    dd($user->getCurrentWeek());
    

    【讨论】:

    • $thing->load('relationshipName') 正是我所需要的。我在调用save() 后直接生成的PDF 中使用延迟加载的关系。谢谢!
    【解决方案3】:

    只是添加到@patricus 答案...

    保存/创建/更新后,您还可以清空所有缓存的关系数据,如下所示: $user->setRelations([]);

    或有选择地: $user->setRelation('weeks',[]);

    之后,只有在需要时才会再次延迟加载数据: $user->weeks

    这样您就可以继续使用延迟加载。

    【讨论】:

    • 很好的答案! (eat this stackoverflow)
    猜你喜欢
    • 2018-06-28
    • 2017-10-25
    • 2015-08-28
    • 1970-01-01
    • 2021-12-10
    • 2018-01-03
    • 1970-01-01
    • 2020-07-24
    • 2020-11-18
    相关资源
    最近更新 更多