急切加载对 Laravel 中的模型事件/启动有一些意想不到的副作用

Posted

技术标签:

【中文标题】急切加载对 Laravel 中的模型事件/启动有一些意想不到的副作用【英文标题】:Eager loading has some unexpected side effects on Model events/ booting in Laravel 【发布时间】:2013-12-07 15:53:51 【问题描述】:

我正在尝试创建一些测试。

这是我的测试类:

class ExampleTest extends TestCase 

    public function setUp()
    
        parent::setUp();
        Artisan::call('migrate');
        $this->seed();
        Auth::loginUsingId(1);
    
    public function testActionUpdateNew()
    
        $action = new Action(Array());
        $action->save();
        var_dump($action->id);
        Action::with('reponses','contact','user','etudiant','entreprise','etude')->findOrFail($action->id);
    
    public function testEtudes()
    
        $etudes=Etude::all()->toArray();
        $this->assertCount(10, $etudes, "Nombre d'études incorrectes");
        $numEtudes=count($etudes);
        //Buggy part
        $etude= Etude::create(Array());
        var_dump($etude->id);
        $etudes=Etude::all()->toArray();
        $this->assertCount(11, $etudes, "Nombre d'études incorrectes");
        //10+1 should equal to 11 but it hasnt updated
    

没有通过的测试是第二个:我数了数eloquent Objects Etudes的数量,一开始是10个,然后我在数据库中添加一个etude(使用Etude::create()),对象被创建,因为 $etude->id 给出了一个实数。但是,练习曲的数量没有更新。

当我从 Action::with('reponses',...) 中的急切加载中删除“练习曲”时,问题确实消失了

这是Action类中的练习曲关系:

public function etude() 
    return $this->belongsTo('Etude');

你们知道在 laravel 中预加载是否会出现这种奇怪的行为以及如何解决这个问题吗?

编辑

我发现 with('etude') 调用具有删除注册到 Eloquent 模型的事件的操作:

练习曲的引导方法:

public static function boot()

    parent::boot();

    static::creating(function($etude)
        
                       var_dump("creating etude"); //This doesn't get executed even when I run Etude::create(Array());
        
    );

所以如果我在 testEtudes 的开头添加 Etude::boot(),它会再次起作用。这还是很奇怪。

急切加载对事件或启动方法有任何影响吗?还是每次测试后都不会自动调用boot方法?

【问题讨论】:

您确定它已保存/$action->id 是有效值吗?异常消息是什么? 嗨,当我添加 var_dump($action->id); 时,我得到 2836(一个真实值),异常消息是一个空字符串:“”(这是正常的,因为它是扔在这里:laravel.com/api/…) 你确定它完全抛出异常吗?我希望看到堆栈跟踪。我在 Laravel 中的单元测试方面做得不多,但也许它只是没有打印任何东西。尝试用 echo 交换 return。 返回 echo 并不能解决问题。堆栈跟踪可以在这里找到:pastebin.com/QDNcBGhy 这真的很奇怪,因为当我将该代码放在 ExampleTest 类的顶部时,它通过了。 【参考方案1】:

在 Laravel 测试中,事件调度器在每次测试之间都会重置,但模型仍然只启动一次,因为它们过着非常独立的生活。这意味着在每次测试之间,模型侦听器都会被删除,但不会重新注册。解决方案是不使用boot() 来注册模型事件,而是将它们放在一个单独的文件中 - 服务提供者或 app/start/global.php 中包含的文件(app/events.php 是一个常见的文件) .

【讨论】:

以上是关于急切加载对 Laravel 中的模型事件/启动有一些意想不到的副作用的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 动态关系 - 在急切加载时访问模型属性

急切加载 Laravel Eloquent 相关模型

Laravel 混合获取 Eloquent 急切加载嵌套多个模型

尝试从子模型重新访问父模型的 laravel 多级关系急切加载问题

带有约束的 Laravel 嵌套急切加载

带有嵌套关系的 Laravel 急切加载