Doctrine 固定装置加载,有问题设置引用(外键)违反 -not-null 约束

Posted

技术标签:

【中文标题】Doctrine 固定装置加载,有问题设置引用(外键)违反 -not-null 约束【英文标题】:Doctrine fixtures load, having issue setting references (foreign key) violates -not-null constraint 【发布时间】:2020-08-20 15:29:30 【问题描述】:

我正在使用 Doctrine Fixtures 将一些数据加载到我的数据库中, 有 3 个不同的表 User、Theme 和 Sous_Theme,最后两个表有外键,Theme as (user.id) 和 Sous_Theme 作为两个外键 (user.id & theme.id)

我的AppFixtures.php 类的设置方式是每个模型值都已经以这种方式写入:

 private const USERS = [
      [
          'last_name' => 'Goodman',
          'first_name'=> 'Robert',
          'email' => 'robert@foobar.com',
          'job' => 'Admin_Tester',
          'password' => 'blablablablablbal',
          'username' => 'blablablabla',
          'roles' => [USER::ROLE_ADMIN]
      ]...
]



private const THEMES =
    [
        ['name' => 'A theme'],
        ['name' => ' A theme 2']
  .....
]

private const SOUSTHEMES = [
    [
        'name' => 'blablabla',
        'part1' => true, //boolean
        ...
    ],

在编写 SOUSTHEMES 部分之前,我已经加载了用户和主题值以及它完美工作的参考:

public function loadTheme(ObjectManager $manager)
    
        foreach (self::THEMES as $themeDate)
            $theme = new Theme();
            $theme->setName($themeDate['name']);
            $date = new \DateTime();
            $date->modify('-'. rand(0, 10) . 'day');
            $theme->setCreatedAt($date);
            //// Setting user Id into our Theme table.
            $theme->setUser($this->getReference(
                self::USERS[rand(0, count(self::USERS) - 1)]['last_name']));
            $manager->persist($theme);
        
        $manager->flush();
    

现在我正在尝试使用引用 theme.id 和 user.id 加载 sousthemes:

public function loadSousThemes(ObjectManager $manager)
        foreach (self::SOUSTHEMES as $sousthemeData)
            $sousthemes = new SousTheme();
            $sousthemes->setName($sousthemeData['name']);
            $date = new \DateTime();
            $date->modify('-'. rand(0, 10) . 'day');
            $sousthemes->setCreatedAt($date);
   

            //// Setting boolean values
            $sousthemes->setPart1($sousthemeData['part_n1']);
  $sousthemes->setUsername($this->setReference(
                self::USERS[rand(0, count(self::USERS) - 1)]['last_name'], $sousthemes));
            $sousthemes->setTheme($this->setReference(
                self::THEMES[rand(0, count(self::THEMES) - 1)]['name'], $sousthemes));

            $manager->persist($sousthemes);
        
        $manager->flush();

我已经开始使用 getReference() 方法,但是我得到了 ref 不存在所以我切换到 addReference() 我得到另一个错误,说 ref 已经存在我需要使用 setReference() 来覆盖它所以我将我的方法更改为setReference() 现在我得到一个错误

SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "theme_id" violates not-null constraint 

我在user.id 上也遇到了同样的错误。 getReference 在我将 user.id 值添加到我的主题时完美运行,但它不适用于 southeme 我试图找出原因,是因为我正在注入两个外键,这是我非常怀疑的,我不知道我错过了什么,在任何人说之前大声笑是的,我首先以正确的顺序加载我的价值观,然后是主题,然后是sousthemes:

public function load(ObjectManager $manager)
    
        $this->loadUsers($manager);
       $this->loadTheme($manager);
       $this->loadSousThemes($manager);
    

这里是 UploadUsers 函数:

public function loadUsers(ObjectManager $manager)
    
        foreach (self::USERS as $userData)
        
            $user = new User();
            $user->setFirstName($userData['first_name']);
            $user->setLastName($userData['last_name']);
            $user->setEmail($userData['email']);
            $user->setJob($userData['job']);
            $user->setPassword($this->passwordEncoder->
            encodePassword($user, $userData['password']));
            $user->setUsername($userData['username']);
            $user->setCreatedAt(new \DateTime());
            $user->setRoles($userData['roles']);
            $this->addReference($userData['last_name'], $user);
            $manager->persist($user);
        
        $manager->flush();
    

【问题讨论】:

还显示 loadUsers 方法。在您的 loadSousThemes 中,这些绝对应该是使用的 getReference 方法,而不是 setReference。 @blahy 刚刚添加了 loaduser 函数,是的,我知道它应该是 getReference,但是当我使用该方法时我得到了一个引用,当我使用 setReference 时我得到一个关于 null 约束的 sqlite 错误 【参考方案1】:

首先,您根本不需要 addReference/getReference,因为您使用一个夹具文件。因此,在您的情况下,您可以只保存对象并在设置器中使用它们,例如:

in loadUsers:

public function loadUsers(ObjectManager $manager)
    
        foreach (self::USERS as $userData)
        
            $user = new User();
            ///...
            $manager->persist($user);

            $this->users[$userData['username']] = $user;
        
        $manager->flush();
    

and in loadTheme:

$theme->setUser($this->users[self::USERS[rand(0, count(self::USERS) - 1)]['username']]);

您不需要引用,因为您可以访问对象,当夹具位于单独的文件中时,引用很有用,因为您无法访问在不同夹具文件中创建的对象。 此处描述:https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html#sharing-objects-between-fixtures。

但是假设您想使用引用,我将尝试提供可以修复您已有代码的指针。您说通过引用加载用户适用于主题:

$theme->setUser($this->getReference(self::USERS[rand(0, count(self::USERS) - 1)]['last_name']));

之所以有效,是因为您在 loadUsers: 中添加了引用:

$this->addReference($userData['last_name'], $user);

所以在loadUsers 之后,您就有了这些参考资料:

User objects:
 - Goodman
 - ...

现在,无论何时您调用$this->getReference('Goodman');,您都会获得可以在setter 中使用的User 对象,例如。设置用户();

但您从未在loadTheme 中调用addReference 来保存对主题对象的引用。

addReference 添加到loadTheme

public function loadTheme(ObjectManager $manager)
    
        foreach (self::THEMES as $themeDate)
            $theme = new Theme();
            $theme->setName($themeDate['name']);
            // ...
            $theme->setUser($this->getReference(
                self::USERS[rand(0, count(self::USERS) - 1)]['last_name']));
            $manager->persist($theme);

            $this->addReference($theme->getName(), $theme);
        
        $manager->flush();
    

所以在loadUsersloadThemes 之后,这些引用将可用:

User objects:
 - Goodman
 - ...

Theme objects:
 - A theme
 - A theme 2
 - ...

最后在你的loadSousThemes:

$sousthemes->setUsername($this->getReference(
                self::USERS[rand(0, count(self::USERS) - 1)]['last_name']));
            $sousthemes->setTheme($this->getReference(
                self::THEMES[rand(0, count(self::THEMES) - 1)]['name']));

请注意,我假设$sousthemes->setUsername() 确实用于设置用户对象,而不仅仅是用户名(为什么不称为 setUser?)

【讨论】:

谢谢!是的,我刚刚意识到使用需要应用于主题加载器的 addreference 方法。现在更有意义了

以上是关于Doctrine 固定装置加载,有问题设置引用(外键)违反 -not-null 约束的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 3.3 Doctrine Fixtures 加载跳过 SQL 视图

如何从 Doctrine Fixture 参考中获取实体?

不同阶段有不同的 initial_data 固定装置(测试与生产)

Symfony 固定装置和多对多关系(学说)

Doctrine(Symfony) 加载夹具,参考不存在

Symfony 4 - 加载动态用户角色的固定装置