Search code examples
phpdatabaselaravellaravel-5laravel-seeding

Seeding many-to-many relationship with model factory in laravel - column cannot be null error


Given that I have the following tables:

  • users
  • questions
  • tags
  • question_tag my pivot table with two fields: question_id & tag_id

and these are my model relationships:

User

public function questions()
{
    return $this->hasMany(Question::class);
}

Question

public function user()
{
    return $this->belongsTo(User::class);
}

public function tags()
{
    return $this->belongsToMany(Tag::class);
}

Tag

public function questions()
{
    return $this->belongsToMany(Question::class);
}

I have setup the database model factory correctly for each models.

With my seeder, here's what I am trying to achieve:

  1. Seed 10 dummy users
  2. For each dummy user, seed 10 dummy questions
  3. For each dummy question, associate it with up-to 5 random tags

To achieve the above three goals, I wrote the following database seeder:

// Seed dummy users
factory(App\User::class, 10)->create()->each(function($user)
{
    // With dummy questions
    $user->questions()->saveMany(factory(App\Question::class, 10)->make()->each(function($question)
    {
        // With dummy tags
        $question->tags()->sync(factory(App\Tag::class, 5)->make());
    }));
});

When this runs, I am getting the following error:

[Illuminate\Database\QueryException] SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'question_id' cannot be null (SQL: i nsert into question_tag (question_id, tag_id) values (, 1))

[PDOException] SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'question_id' cannot be null

How do you seed a pivot table, whilst creating records via the database model factory?


This question is related to another question I asked - but now I am getting a different error.


Solution

  • I've solved it like this:

    <?php
    
    use Illuminate\Database\Seeder;
    
    class DummyDataSeeder extends Seeder
    {
        public function run()
        {
            // Seed dummy tags
            factory(App\Tag::class, 10)->create();
            $tagIds = DB::table('tags')->pluck('id')->toArray();
    
            // Seed dummy users
            factory(App\User::class, 10)->create()->each(function($user) use($tagIds)
            {
                // With dummy questions
                $user->questions()->saveMany(factory(App\Question::class, 3)
                ->create(['user_id' => $user->id])->each(function($question) use($tagIds)
                {
                    // With dummy tags
                    $question->tags()->sync(array_random($tagIds, mt_rand(1, 5)));
                }));
            });
        }
    }
    

    Maybe there's a better a way to do this; but this is working for me.