Search code examples
sqlitedoctrinesymfony4fixtures

sqlite: Fixtures load null instead of string - NOT NULL constraint failed


I have a simple Entity consisting of just one field "name":

/**
 * @ORM\Table(name="gender")
 * @ORM\Entity
 * @codeCoverageIgnore
 */
class Gender
{
    public const FEMALE = 'female';
    public const MALE = 'male';
    public const OTHER = 'other';

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=15, nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private string $name;

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): Gender
    {
        $this->name = $name;

        return $this;
    }
}

For this class I try to generate fixtures and insert them into a sqlite db for testing:

use App\Entity\Gender; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager;

class GenderFixtures extends Fixture
{

    public function load(ObjectManager $manager)
    {
        $genders = [Gender::FEMALE, Gender::MALE, Gender::OTHER];

        foreach ($genders as $genderName) {
            echo $genderName . PHP_EOL;

            $gender = (new Gender())
                ->setName($genderName);
            $manager->persist($gender);
        }

        $manager->flush();
    }
}

When I call

 bin/console  doctrine:fixtures:load --env=test

I get this:

female
male
other

In AbstractSQLiteDriver.php line 39:

  An exception occurred while executing 'INSERT INTO gender (name) VALUES (null)':             

  SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: gender.name 

So as you can see there are the three strings I want to use as name. Why are they not used by the Fixture in the insert statement?

Symfony 4.4, PHP 7.4.1, Doctrine Fixtures 3.3.0


Solution

  • It seems like fixtures filling a sqlite db cannot deal with primary keys, which are not auto incremented integers.

    The same fixtures worked on a MySql database like a charm. So as long as I want to use the sqlite db for unittests, I added to all my entities

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="smallint", options={"unsigned":true})
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private ?int $id = null;
    
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=15, nullable=false)
     */
    private string $name;
    

    And of course I had to change the naming and the referenced column for the connected entities.

    Still I don't know if it is wise to use a different db for testing than for dev and prod. Problems like this show that it is not an ideal solution.

    When I did run a similar application locally, I just had another MySql db for testing. Now I run this app in docker and had troubles in using a different db for tests, than for dev. Hence the sqlite solution....