I'm running into an issue where the ->attach() method will bulk insert for one model but not another and thereby creating an n+1 insert of hundreds or potentially thousands of queries.
For example, in one scenario I have both a Collection model (not to be confused with a collection in Laravel) and a Account model with a belongsToMany relationship. I'm attaching a bunch of accounts to a collection with the following code:
$collection = Collection::findOrFail($data['collection']);
$chunks = $selectedAccounts->diff($collection->accounts)->pluck('id')->chunk(500);
$chunks->each(fn ($chunk) => $collection->accounts()->attach($chunk));
This works great and does one bulk insert.
Now, in another scenario, I have both a Campaign model and a Account model, again with a belongsToMany relationship. I'm attaching a bunch of accounts to a campaign with the following code:
$collection = Collection::findOrFail($data['collection']);
$chunks = $collection->accounts->diff($this->campaign->accounts)->pluck('id')->chunk(500);
$chunks->each(fn ($chunk) => $this->campaign->accounts()->attach($chunk));
This unfortunately is generating one insert query for each account for some reason and I don't understand why? The only difference here is that on the first scenario, the relationship is defined without a pivot model while the second does have a pivot model.
Collection.php
public function accounts(): BelongsToMany
{
return $this->belongsToMany(Account::class, 'crm.account_collection')->withTimestamps();
}
Campaign.php
public function accounts(): BelongsToMany
{
return $this->belongsToMany(Account::class, 'crm.account_campaign')
->using(AccountCampaign::class)
->withPivot(['campaign_stage_id', 'sort_order'])
->withTimestamps();
}
Is this the reason or am I missing something?