+ Start a Discussion
cambart14cambart14 

Insert Record then Update Current Record

We have a product specification form (Product_Brief__c) that once saves needs to insert a Project.  Once that Project is inserted, I need to take the Project ID and update the Product Brief with that ID.

The code below works properly to create a Project.  When I try and use that Project ID to update the Product Brief (last two lines of code) it gives me this error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY.

Any help here would be much appreciated!
trigger ProjectCreation on Product_Brief__c (after insert, after update) {

    Product_Brief__c pb = [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_Product__c, Related_Project__c FROM Product_Brief__c WHERE ID =: trigger.new];
    
    Project__c p = new Project__c();
    p.RecordTypeID = '012W00000008nXT';
    p.Related_Opportunity__c = pb.Opportunity__r.ID;
    p.Sales_Rep__c = pb.Opportunity__r.Owner.ID;
    p.Project_Description__c = pb.Select_Product__c;
    p.Project_Category__c = 'Bags and Tubing Sets';
	p.Status__c = 'Active';
    p.Start_Date_and_Time__c = System.Now();
    
    insert p;
    
    pb.Related_Project__c = p.ID;
    
    update pb;
}
Best Answer chosen by cambart14
cambart14cambart14
Working code as follows:

Trigger:
trigger ASIProjectCreation on Product_Brief__c (after insert, after update) {
    
    Product_Brief__c pb = [SELECT Related_Project__c FROM Product_Brief__c WHERE ID =: trigger.new];
    if(pb.Related_Project__c == NULL){
    
    ProductBriefFutureHandler.createProject(Trigger.newMap.keyset()); 
    
    }

}
Class:
public class ProductBriefFutureHandler{
    @future
    public static void createProject(Set<ID> productBriefIds){
    Map<Id,Project__c> prdBrfidWithPrjMap=new Map<Id,Project__c>();
    For( Product_Brief__c  pb : [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_BPC_Product_ASI__c, Related_Project__c FROM Product_Brief__c WHERE ID  IN : productBriefIds]){
          Project__c prj = new Project__c();
          prj.RecordTypeID = Project__c.sObjectType.getDescribe().getRecordTypeInfosByName().get('ASI').getRecordTypeId();  
          prj.Related_Opportunity__c = pb.Opportunity__r.ID;
          prj.Sales_Rep__c = pb.Opportunity__r.Owner.ID;
          prj.Project_Description__c = pb.Select_BPC_Product_ASI__c;
          prj.Project_Category__c = 'ASI Bags and Tubing Sets';
          prj.Status__c = 'Active';
          prj.Start_Date_and_Time__c = System.Now();
          prdBrfidWithPrjMap.put(pb.Id,prj);
      }
     Insert prdBrfidWithPrjMap.values();
      List<Product_Brief__c>  pbfList=new List<Product_Brief__c>();
      for(Product_Brief__c pbf :[SELECT ID,Related_Project__c FROM Product_Brief__c WHERE Id IN: prdBrfidWithPrjMap.keySet()]){
         pbf.Related_Project__c = prdBrfidWithPrjMap.get(pbf.Id).Id;
         pbfList.add(pbf);
      }
     update pbfList;
     
     }
}


 

All Answers

JayantJayant
1. Create a future method.
2. Call it and pass the Product Brief and Project Ids as arguments to that method.
3. Update the record in that future method. 
4. Add a check in your trigger to skip the logic if context is future [If (System.isFuture() == true)].
ManojjenaManojjena
Hi Cambart,

Please try with below code and replace YourRecordTypeName with original recordtype name which you want to assign because we should not use hard code Id .
 
trigger ProjectCreation on Product_Brief__c (after insert, after update) {
  Map<Id,Project__c> prdBrfidWithPrjMap=new Map<Id,Project__c>();
  For( Product_Brief__c  pb : [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_Product__c, Related_Project__c FROM Product_Brief__c WHERE ID  IN =: trigger.new]){
       Project__c prj = new Project__c();
		prj.RecordTypeID = Project__c.sObjectType.getDescribe().getRecordTypeInfosByName().get('YourRecordTypeName').getRecordTypeId();  
		prj.Related_Opportunity__c = pb.Opportunity__r.ID;
		prj.Sales_Rep__c = pb.Opportunity__r.Owner.ID;
		prj.Project_Description__c = pb.Select_Product__c;
		prj.Project_Category__c = 'Bags and Tubing Sets';
		prj.Status__c = 'Active';
		prj.Start_Date_and_Time__c = System.Now();
		prdBrfidWithPrjMap.put(pb.Id,prj);
    }
   Insert prdBrfidWithPrjMap.values();
    List<Product_Brief__c>  pbfList=new List<Product_Brief__c>();
    for(Product_Brief__c pbf :[SELECT ID,Related_Project__c FORM Product_Brief__c WHERE Id IN: prdBrfidWithPrjMap.keySet()]){
	   pbf.Related_Project__c = prdBrfidWithPrjMap.get(pbf.Id).Id;
	   pbfList.add(pbf);
	}
   update pbfList;
 }
Let me know any issue .
 
vinodrajput1.3947816596948318E12vinodrajput1.3947816596948318E12
You have written trigger on Product_Brief__c object and you are trying to updating same object means your object is updating multiple times i.e recursive thats why system showing error CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY and excced the limit  Solution is: You have to use static flag concept here to avoid recursive call.Decalare one static flag in another class and check 
if(Static flag==true){
      Set static flag to =false
     update object;
}
Mudasir WaniMudasir Wani

Dear Cambart,

If you need to update the same object record the ways possible are 
1. Time based workflow
2. Future method 

Future method is used as per the following approach.
 
trigger ProjectCreation on Product_Brief__c (after insert, after update) {
	ProductBriefHandler.createProject(Trigger.new);
}

//Your Apex class

public class ProductBriefHandler(){
	
	public void createProject(List<Product_Brief__c> productBrief){
		Set<Id> productBriefIds = new Set<Id>();
		for(Product_Brief__c projBrifRec : productBrief){
			productBriefIds.add(projBrifRec.id);
		}
		ProductBriefFutureHandler.createProject(productBriefIds);
	}
}
//Create a future handler
public class ProductBriefFutureHandler(){
	@future 
	public static void createProject(Set<Id> productBriefIds){
		List<Product_Brief__c> projBrifList = [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_Product__c, Related_Project__c FROM Product_Brief__c WHERE ID =: productBriefIds];
		for(Product_Brief__c projBrif : projBrifList){
			Project__c proj = new Project__c();
			proj.RecordTypeID = '012W00000008nXT';
			proj.Related_Opportunity__c = projBrif.Opportunity__r.ID;
			proj.Sales_Rep__c = projBrif.Opportunity__r.Owner.ID;
			proj.Project_Description__c = projBrif.Select_Product__c;
			proj.Project_Category__c = 'Bags and Tubing Sets';
			proj.Status__c = 'Active';
			proj.Start_Date_and_Time__c = System.Now();
			proj.Related_Project__c = proj.ID;
		}
		update projBrifList;
	}
}



Donot forget to select best answer to make our efforts visible in the developer forum.
Please mark this as solution by selecting it as best answer if this solves your problem, So that if anyone has this issue this post can help

 
cambart14cambart14
Thanks everyone for your input!

@Mudasir Wani I was able to successfully create the two apex class.  When trying to save the trigger you have indicated I run into this error below.  Is this because it is trying to pass an ID into a List?  Any insight you have would be appreciated.

Error: Compile Error: Method does not exist or incorrect signature: ProductBriefHandler.createProject(List<Product_Brief__c>) at line 4 column 5
trigger ASIProjectCreation on Product_Brief__c (after insert, after update) {   
    ProductBriefHandler.createProject(trigger.new);
}

 
JayantJayant
Please mark the method - ProductBriefHandler.createProject() as Static.

public Static void createProject(List<Product_Brief__c> productBrief){
JayantJayant
You may also get rid of the class - ProductBriefHandler, its not really required.

Just use this in your trigger - 

ProductBriefFutureHandler.createProject(Trigger.newMap.keyset());
cambart14cambart14
@Jayant, thank you that solved the error message I was getting.

I now have the trigger and two classes created.  When I create a new Product Brief, not project is created.  I'm not getting any error message or anything else.  Below is the full code.

Trigger:
trigger ASIProjectCreation on Product_Brief__c (after insert, after update) {

    ProductBriefHandler.createProject(Trigger.new);

}
Class:
public class ProductBriefHandler{
    
    public Static void createProject(List<Product_Brief__c> productBrief){
        Set<Id> productBriefIds = new Set<Id>();
        for(Product_Brief__c projBrifRec : productBrief){
            productBriefIds.add(projBrifRec.id);
        }
        ProductBriefFutureHandler.createProject(productBriefIds);
    }
}
Class
public class ProductBriefFutureHandler{
    @future 
    public static void createProject(Set<ID> productBriefIds){
        List<Product_Brief__c> projBrifList = [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_BPC_Product_ASI__c, Related_Project__c FROM Product_Brief__c WHERE ID =: productBriefIds];
        for(Product_Brief__c projBrif : projBrifList){
            Project__c proj = new Project__c();
            proj.RecordTypeID = Project__c.sObjectType.getDescribe().getRecordTypeInfosByName().get('ASI').getRecordTypeId();
            proj.Related_Opportunity__c = projBrif.Opportunity__r.ID;
            proj.Sales_Rep__c = projBrif.Opportunity__r.Owner.ID;
            proj.Project_Description__c = projBrif.Select_BPC_Product_ASI__c;
            proj.Project_Category__c = 'ASI Bags and Tubing Sets';
            proj.Status__c = 'Active';
            proj.Start_Date_and_Time__c = System.Now();    
        }
        update projBrifList;
    }
}


 
JayantJayant
Just observed that the snippet is not complete and you will need to tweak it.
1. Projects are not being inserted (this needs to be added).
2. Project Id is not being set on Product Brief but rather on Project itself (this needs to be replaced with correct code).
cambart14cambart14
Working code as follows:

Trigger:
trigger ASIProjectCreation on Product_Brief__c (after insert, after update) {
    
    Product_Brief__c pb = [SELECT Related_Project__c FROM Product_Brief__c WHERE ID =: trigger.new];
    if(pb.Related_Project__c == NULL){
    
    ProductBriefFutureHandler.createProject(Trigger.newMap.keyset()); 
    
    }

}
Class:
public class ProductBriefFutureHandler{
    @future
    public static void createProject(Set<ID> productBriefIds){
    Map<Id,Project__c> prdBrfidWithPrjMap=new Map<Id,Project__c>();
    For( Product_Brief__c  pb : [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID, Select_BPC_Product_ASI__c, Related_Project__c FROM Product_Brief__c WHERE ID  IN : productBriefIds]){
          Project__c prj = new Project__c();
          prj.RecordTypeID = Project__c.sObjectType.getDescribe().getRecordTypeInfosByName().get('ASI').getRecordTypeId();  
          prj.Related_Opportunity__c = pb.Opportunity__r.ID;
          prj.Sales_Rep__c = pb.Opportunity__r.Owner.ID;
          prj.Project_Description__c = pb.Select_BPC_Product_ASI__c;
          prj.Project_Category__c = 'ASI Bags and Tubing Sets';
          prj.Status__c = 'Active';
          prj.Start_Date_and_Time__c = System.Now();
          prdBrfidWithPrjMap.put(pb.Id,prj);
      }
     Insert prdBrfidWithPrjMap.values();
      List<Product_Brief__c>  pbfList=new List<Product_Brief__c>();
      for(Product_Brief__c pbf :[SELECT ID,Related_Project__c FROM Product_Brief__c WHERE Id IN: prdBrfidWithPrjMap.keySet()]){
         pbf.Related_Project__c = prdBrfidWithPrjMap.get(pbf.Id).Id;
         pbfList.add(pbf);
      }
     update pbfList;
     
     }
}


 
This was selected as the best answer
JayantJayant
My version of the class would be - 
---------------------------------------------------------------------
public class ProductBriefFutureHandler {

    @future
    public static void createProject(Set<Id> pbIds){
        List<Product_Brief__c> pbList = new List<Product_Brief__c>(); //this will hold the inserted or updated records
        Map<Id, Project__c> pbVsProjects = new Map<Id, Project__c>(); //this will help us map Projects to their Products
        //query the products
        pbList = [SELECT ID, Opportunity__r.ID, Opportunity__r.Owner.ID Select_BPC_Product_ASI__c, Related_Project__c FROM Product_Brief__c WHERE ID IN :pbIds];

        //iterate over each product and create a corresponding project
        for(Product_Brief__c pb : pbList){
            Project__c proj = new Project__c();
            proj.RecordTypeID = Project__c.sObjectType.getDescribe().getRecordTypeInfosByName().get('ASI').getRecordTypeId();
            proj.Related_Opportunity__c = pb.Opportunity__r.ID;
            proj.Sales_Rep__c = pb.Opportunity__r.Owner.ID;
            proj.Project_Description__c = pb.Select_BPC_Product_ASI__c;
            proj.Project_Category__c = 'ASI Bags and Tubing Sets';
            proj.Status__c = 'Active';
            proj.Start_Date_and_Time__c = System.Now();
            pbVsProjects.put(pb.Id, proj);    //put the product and associated project in the map
        }
        insert pbVsProjects.values();    //insert the projects, after insertion Id field would be populated in the inserted list
        
        //iterate over each product again to map to correct project
        for(Product_Brief__c pb : pbList) {
            pb.Related_Project__c = pbVsProjects.get(pb.Id).Id;    //get() shall give us the correct Project and then we need to traverse to Id
        }        
        update pbList;    //update the products
    }
}

------------------------------------------------------------------------------------------
Please go through the comments to understand why its so. Forgive me for using Product instead of Product Brief.


I see the following challenges in this approach now - 

1. The update on Product Briefs in last statement of the future method would trigger the trigger again (since its on After Update event as well).
Solution would be the below change in trigger - 

---------------------------------------------------------------------
trigger ASIProjectCreation on Product_Brief__c (after insert, after update) {
    //skip the snippet below if context is Future i.e. trigger has been called from a transaction executing within a Future method
    if(!System.isFuture()){
        ProductBriefFutureHandler.createProject(Trigger.newMap.keySet());
    }
}
-----------------------------------------------------------------------
We do not need the ProductBriefHandler class anymore, you may want to delete that.
--------------------------------------------------------------------------------------------------------------------------------------

Everything should work fine now except following - 

1. You are creating a new Project everytime a Product Brief is being inserted or modified. This is a logical flaw.
There should be some criteria to determine when to create a new Project for example on update of Product Brief only when certain fields change in a specific way as your Product Brief already has an associated Project that you had created while creating the Product Brief itself.
Fix this logical flaw and you are rocking :)

2. In case you expect recursion for example say you create a Product Brief and then a workflow fires which does a field update on it, this should trigger your trigger again for update event (though it has already executed for insert and logically is not required to run again), you may want to introduce some Static variables to control the behavior (for time being you are good to go if you already don't have a recursive scenario in place).
JayantJayant
Your working code that you have chosen as Best Answer is not bulkified. It would run only with a batch size of 1 correctly. If you are loading data via API or running a mass update, it may not work correctly.
cambart14cambart14
@Jayant

Thanks for the insight; we won't be loading any Product Brief records via API.  Though, I am curious what piece of the code is not bulkified.  The DML statements are all outside of the FOR loops and I'm not immediately seeing anything else out of place.
JayantJayant
The code in the trigger is incorrect.

1. Product_Brief__c pb = [SELECT Related_Project__c FROM Product_Brief__c WHERE ID =: trigger.new];
 if(pb.Related_Project__c == NULL){

This will work only till batch size is 1. If batch size is 2 or more, your query is going to return a list and you are going to run in an exception. Also, pb.Related_Project__c will throw exception as index is not specified.

2. If you even include an index in above, you would just be deciding on calling the Class method based on 1st record. You should filter the Ids that do not have Project and only pass those Ids to the method, not all records in Trigger.New.