Home > other >  How to seed tables orderly to avoid "Integrity constraint violation" in Laravel 9.x
How to seed tables orderly to avoid "Integrity constraint violation" in Laravel 9.x

Time:11-27

I have a bookstore project, and have 2 table: publishers and books. These is my two migrate file for books and publishers.

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->integer('available_quantity');
            $table->string('isbn');
            $table->string('language');
            $table->integer('total_pages');
            $table->float('price');
            $table->string('book_image');
            $table->string('description')->nullable();
            $table->date('published_date');
            $table->unsignedBigInteger('publisher_id');
            $table->foreign('publisher_id')->references('id')->on('publishers');
            $table->unique('isbn');
            $table->softDeletes();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('books');
    }
}
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('publishers', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name')->unique();
            $table->string('address');
            $table->string('phone');
            $table->string('description')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('publishers');
    }
};

As you see, books has a foreign key publisher_id, which has reference to publishers on id, so when I run php artisan db:seed,both tables will be seeded at the same time, but as we know, the publishers table should be seeded before books table be. So are there any way to seed tables orderly (not at the same time) ?

CodePudding user response:

Well you can actually create the related publisher when creating the books in a seeder.

// You can use the "for()" if you define it in a child table and "has()" when define in a parent table.

Book::factory(10)->for(Publisher::factory()->create())->create(); // will create 10 books but only belongs to one publisher

Publisher::factory(10)->has(Book::factory()->count(10))->create(); // will create 10 books in each publisher. it means that you will have a 100 books.

You can also directly define it in the Database\Factories\BookFactory::class

public function definition()
{
    return [
        'publisher_id' => Publisher::factory(), //add this to the BookFactory::class
    ];
}
Book::factory(10)->create(); // will create 10 book but also create 10 publisher

Eloquent Factories: Factory Relationship

CodePudding user response:

Personally I prefer to make Publisher seeder first, then in set the value of Book's publisher_id in the factory to be random from the existing Publisher.

  1. Create 100 Publisher, or any amount you wish to set

    Publisher::factory()->count(100)->create();
    
  2. Ramdomly set publisher_id from the existing records

    return [
       // ....
       'publisher_id' => Publisher::inRandomOrder()->first()->id
    ];
    

CodePudding user response:

You have a file named DatabaseSeeder. You can choose the order of the seeder there:

public function run()
    {
        $this->call([
            PublisherSeeder::class,
            BookSeeder::class,
        ]);
    }

If you put PublisherSeeder first, the seeder will be called before BookSeeder and you won't have the constraint integretity error.

  • Related