-1

Here is the table stucture

  • Table A
  • Table B has foreign key a_id
  • Table C has foreign key a_id and b_id

I am trying to Seed these three tables with Eloquent Relationships

Here is my code structure

class A extends Model
{
    use HasFactory;

    protected $fillable = [...];

    public function b()
    {
        return $this->hasMany(B::class);
    }

    public function c()
    {
        return $this->hasMany(C::class);
    }
}
class B extends Model
{
    use HasFactory;

    protected $fillable = [...];

    public function c()
    {
        return $this->hasMany(C::class);
    }
}
class C extends Model
{
    use HasFactory;

    protected $fillable = [...];
}
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        \App\Models\A::factory(5)
            ->has(\App\Models\B::factory(2))
            ->has(\App\Models\C::factory(1))
            ->create();
    }
}

Error:

SQLSTATE[HY000]: General error: 1364 Field 'b_id' doesn't have a default value (SQL: insert into c (... a_id, updated_at, created_at)

matiaslauriti
  • 7,065
  • 4
  • 31
  • 43
Ratul
  • 43
  • 2
  • 8

1 Answers1

0

Your seeder will create 5 A models.

For each of these 5 A, it's going to try and do two things

  • create 2 B, passing in a_id.
  • create 1 C, passing in a_id, but not passing any b_id.

Here's how each of those A models would look like.

// A model
{
    id: 1
    b: [
        // B model
        {
            id: 1,
            a_id: 1
        },
        // B model
        {
            id: 2,
            a_id: 1
        },
    ],
    c: [
        // C model
        {
            id: 1,
            a_id: 1,
        ->  b_id: null <- This will throw the error because b_id is not a nullable column
        },
    ],
}

To fix it you will need to either remove has(\App\Models\C::class) or make a B model to associate with it.

You need to define the belongsTo relationship for this to work.

# B model
public function a()
{
    return $this->belongsTo(A::class);
}
# C model
public function a()
{
    return $this->belongsTo(A::class);
}

public function b()
{
    return $this->belongsTo(B::class);
}

For example

use App\Models\A;
use App\Models\B;
use App\Models\C;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $b = B::factory()->for(A::factory())->create();

        A::factory(5)
            ->has(B::factory(2))
            ->has(C::factory(1)->for($b))
            ->create();
    }
}

You could also not create everything in one statement.

use App\Models\A;
use App\Models\B;
use App\Models\C;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $A_models = A::factory(5)
            ->has(B::factory(2))
            ->create();

        foreach ($A_models as $A) {
            $b_id = $A->b->pluck('id')->random();
            $c = C::factory()->make(['b_id' => $b_id]);

            $a->c()->save($c);
        }
    }
}
IGP
  • 14,160
  • 4
  • 26
  • 43
  • So I have Merchant, Shop and Campaign as A,B and C. When is try this ` $shop = Shop::factory()->for(Merchant::factory())->create(); Merchant::factory(5) ->has(Shop::factory(2)) ->has(Campaign::factory(1)->for($shop)) ->create(); ` its shows BadMethodCallException Call to undefined method App\Models\Shop::merchant() – Ratul Feb 09 '23 at 19:22
  • You need to define the `belongsTo` relationship for it to work. `public function merchant() { return $this->belongsTo(Merchant::class); }` in your `Shop` model. – IGP Feb 09 '23 at 19:26
  • Sweet! So it needs both belongsTo in Shop and hasMany in Merchant? – Ratul Feb 09 '23 at 19:31
  • One relational issue thought, _Merchant 1 has Shop 1_ - But in Campaign table one Campain of Shop 1 showing Merchant 4 (who has a different shop) in merchant_id – Ratul Feb 09 '23 at 19:52
  • You should edit your question with those model names and explain better those constraints. – IGP Feb 09 '23 at 21:28
  • I have provided the Model names and explained the constraints with two examples. I did not find what could be a valid reason to downvote my question. Thank you for your help, I will try something different. – Ratul Feb 10 '23 at 09:27