Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jader's avatar
Level 4

Factory to "master detail" relationship

I need help to create a factory to seed a master detail relationship.

I have Purchase model and AssetPurchase model. AssetPurchase would be items of my purchases.

See my code:

return new class extends Migration
{
    public function up()
    {
        Schema::create('asset_purchase', function (Blueprint $table) {
            $table->foreignId('purchase_id')->constrained()->onDelete('cascade');
            $table->foreignId('asset_id')->constrained();
            $table->decimal('price', 8, 2)->default(0);
            $table->decimal('tax', 8, 2)->default(0);
            $table->decimal('due', 8, 2)->default(0);
            $table->decimal('fee', 8, 2)->default(0);
            $table->string('description')->nullable();
            $table->primary(['purchase_id', 'asset_id']);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('item_purchases');
    }
};
class PurchaseFactory extends Factory
{
    public function definition()
    {
        $brokers = Broker::all();

        return [
            'broker_id' => $brokers->random(1)->first()->id,
            'note' => fake()->unique()->randomNumber(),
            'date' => fake()->date(),
        ];
    }
}
class AssetPurchaseFactory extends Factory
{  
    public function definition()
    {
        return [
            'purchase_id' => 0,
            'asset_id' => 0,
            'price' => fake()->randomFloat(2, 50, 200),
            'tax' => fake()->randomFloat(2, 5, 50),
            'due' => fake()->randomFloat(2, 1, 20),
            'fee' => fake()->randomFloat(2, 10, 50),
            'description' => fake()->text(30),
        ];
    }
}
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        Category::factory(3)->create();
        Broker::factory(5)->create();
        $assets = Asset::factory(20)->create();

        Purchase::factory(2)->create()->each(function ($purchase) use ($assets) {
            AssetPurchase::factory(3)->create([
                'purchase_id' => $purchase->id,
                'asset_id' => $assets->random(1)->first()->id
            ]);
        });
    }
}

My challenge is generate a random data to asset_id field.

I tryed

'asset_id' => $assets->random(1)->first()->id

and

'asset_id' => Asset::factory(3)->create()

But my code always generates the same id for asset_id, violating the primary key.

Could you help me?

0 likes
1 reply
newbie360's avatar

this make me some confuse, asset_purchase is pivot table ? AssetPurchase:: is a pivot table model ?

if there is Many-To-Many relationship, why don't just use attach() method ?

and this line, you are hardcoded the value on the create() method, so all is same id, it means create() doesn't loop 3 times to generate the asset_id

            AssetPurchase::factory(3)->create([
                'purchase_id' => $purchase->id,
                'asset_id' => $assets->random(1)->first()->id
            ]);

Please or to participate in this conversation.