You are trying to using a BEFORE
trigger, and in your trigger, you are trying to do a DML call on records that are in the trigger. In BEFORE
triggers, any manipulation you do to the data happens before the records undergo their DML call, so you don't need to perform a DML call on the trigger records -- it's already gonna happen. However, you would need to do a DML call on AFTER
triggers. They happen after the trigger, so anything you do AFTER
the trigger needs to be "saved" via a DML call.
So, for your case, just remove the upsert rows;
and it should work.
To note, I usually use BEFORE
triggers if I need alter data that is being fed into the trigger while I use AFTER
triggers if I need to alter data that is related to the data being fed into the trigger.
BEFORE
Example:
trigger MyCustomObj_beforeTrigger on MyCustomObj__c (before update){
for(MyCustomObj__c m:trigger.new){
//do something to the trigger data
}
}
AFTER
Example:
trigger MyCustomObj_afterTrigger on MyCustomObj__c (afterupdate){
list<myChildObj__c> newChildrenList = new list<myChildObj__c>();
for(MyCustomObj__c m:trigger.new){
newChildrenList.add(new myChildObj__c());
}
insert newChildrenList;
}
Also, one bit of advice on triggers: write all the code you need for your trigger in its own class, and then just call the class in the trigger (and make sure you use all the trigger goodies when you can -- trigger.new
, trigger.old
, trigger.newMap
, trigger.oldMap
, trigger.isInsert
, trigger.isUpdate
, trigger.isDelete
).
It's good to do this to keep your triggers as short and simple as possible. Then, I also recommend that you have only 1 trigger per custom object (so you can easily tell what exactly is being triggered in any situation). And if you need to do separate things in your trigger, just call the classes as needed.
Example:
Class code:
public class trigger_CreateNewChildren(){
public static void CreateNewChildren(map<id,MyCustomObj__c>newMap){
list<MyChildrenObj__c> newChildren = new list<MyChildrenObj__c>();
for(MyCustomObj__c m:newMap.values()){
newChildren.add(new MyChilerenObj__c());
}
insert newChildren;
}//END CreateNewChildren
public static void fieldChangeCheck(map<id,MyCustomObj__c> newMap,map<id,MyCustomObj__c>oldMap){
for(id m:newMap.keyset()){
if(newMap.get(m).field_1__c!=oldMap.get(m).field_1__c)
//do something
}
}//ENDfieldChangeCheck
Trigger code:
Trigger MyCustomObj on MyCustomObj__c(AFTER INSERT,BEFORE UPDATE){
if(trigger.isInsert && trigger.isAfter){
trigger_CreateNewChildren.CreateNewChildren(trigger.newMap);
}
if(trigger.isUpdate && trigger.isBefore){
trigger_CreateNewChildren.fieldChangeCheck(trigger.newMap,trigger.oldMap);
}
}
As you are describing in your question there is no need of much explanation what is going on here. You are trying to update an account in the event of before update which tries to fire the trigger again and again.
This is not accepted and if you really need to do an update in a before trigger(into the triggering object) you can just set that field. It will be effected when the real update happens.
trigger AccountTrigger on Account (before update)
{
for(Account a : [SELECT id FROM Account WHERE id NOT in : trigger.newMap.keySet()])
a.FieldName = value; // no need of DML action since this is before update trigger
}
You better go through the documentation Triggers and Order of Execution. It will explain you much more things related to this topic.
Best Answer
The recursion problem is likely to be the result of the combination of this trigger and another trigger. (Your updated question now shows that and someone can answer about that.)
But the trigger you have posted has the problem that it deletes the Service__c and Accompaniment__c objects for all the Opportunity_car_set__c objects that the trigger is firing for and so is logically wrong for the bulk case (where there are multiple Opportunity_car_set__c objects). Doing the deletes inside the loop will also hit governor limits in the bulk case.
This approach (making use of relationship queries) ensures that it is the related Service__c and Accompaniment__c objects that are deleted: