Search code examples
laravellaravel-6.2

Laravel seed create wrong number of rows in DB


I'm trying to create a seeder with relationships

public function run()
{
    factory(Company::class, 10)->create()->each(function ($company){
        $company->buildings()->saveMany(factory(Building::class, 5)->create()->each(function ($building){
            $building->facilities()->saveMany(factory(App\Models\Facility::class,5)->make());
        }));
    });
}

That code should creeate 10 companies and 5 buildings for each company and 5 facilities for each building. companies 10 buildings 50 facilities 250

but I get

companies 300 buildings 310 facilties 250 which doesn't make sense

my factories:

$factory->define(Company::class, function (Faker $faker) {
    $name = $faker->lastName;
    $company = $name.' Company';
    return [
        'name' => $company,
        'shortName' => $name
    ];
});
$factory->define(Building::class, function (Faker $faker) {
    return [
        'name' => 'Hotel '.$faker->lastName,
        'company_id' => function () {
            return factory(App\Models\Company::class)->create()->id;
        }
    ];
});
$factory->define(Facility::class, function (Faker $faker) {
    $elements = array('lavabo','ducha');

    return [
        'name' => $faker->randomElement($elements).' '.$faker->numerify('Habitacion ###'),
        'building_id' => function () {
            return factory(App\Models\Building::class)->create()->id;
        }
    ];
});

And the databaseSeeder.php

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UserSeeder::class);
        $this->call(CompaniesSeeder::class);
    }
}

Solution

  • Solution

    The problem comes from here:

    $company->buildings()->saveMany(factory(Building::class, 5)->create()->each(function ($building){
        $building->facilities()->saveMany(factory(App\Models\Facility::class,5)->make());
    }));
    

    Every time you create a new building, and facility, it is creating a new company in your factory as well.

    Simply pass the appropriate parameters to your create function to let Faker know to not create new company and building.

    Change from:

    factory(Building::class, 5)->create()
    

    To:

    factory(Building::class, 5)->create(['company_id' => $company->id]);
    

    And apply the same logic for Facility.

    factory(App\Models\Facility::class,5)->make(['building_id' => $building->id])
    

    Side note

    You can also simplify your factories by replacing your callback function like this:

    $factory->define(Building::class, function (Faker $faker) {
        return [
            'name' => 'Hotel '.$faker->lastName,
            'company_id' => factory(Company::class),
        ];
    });