+ Start a Discussion
GRStevenBrookesGRStevenBrookes 

Back to Basics!! Creating a new record with apex

Hi,

 

I am begining to explore apex - its a must i guess - i seem to be at the upper limit of what i can do with SF just using the UI.

 

So...as a start I was hoping one of the kind people on here could help me out......

 

What I am trying to acheive, i belive requires Apex. Effectivly, when the criteria is met on one object, a new record is created on the other record.

 

So, I have the standard Opportunity Object and a Custom Object called 'CS', when the 'Stage' of the Opportunity is set to 'Closed Won', I need a record to be created on 'CS' (which i should point out is linked by a lookup relationship - created by this trigger).

 

I gather, that this is real basic functionality, however was hoping someone could guide me in the right direction, perhaps with some sample code based on the above, so i can begin to understand how it all slots together.

 

 

Many thanks in advance for your help.

 

 

Steve

 

Best Answer chosen by Admin (Salesforce Developers) 
Ankit AroraAnkit Arora

Yes there is a workaround. I am hoping after the trigger when workflow are executed then there must be some filed update is going which again call the trigger, and it all counts in one context.

 

So to avoid the execution of trigger again after the workflow update just create this class :

 

public class myStaticClass
{
    public static boolean flag = false ;
}

 And modify your trigger like this :

 

trigger CreateClass on Opportunity (after insert , before update)
{
    if(!myStaticClass.flag)
    {
        List<CS__c> listCS = new List<CS__c>();
        
        for(Opportunity o : trigger.new)
        {
            if(Trigger.isUpdate)
            {
                if(o.StageName == 'Closed Won' && o.StageName != trigger.oldMap.get(o.Id).StageName)
                {
                  listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
                }
            }
            if(Trigger.isInsert)
            {
                if(o.StageName == 'Closed Won')
                {
                  listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
                }
            }
        }
    
        if(listCS.size() > 0)
        {
            insert listCS;
        }
        myStaticClass.flag = true ;
    }
}

 

Thanks

Ankit Arora

 Blog | Facebook | Blog Page

All Answers

Shashikant SharmaShashikant Sharma

Use this trigger change API names as per yours in it

trigger createNewCS on Opportunity (before update) 
{
    List<CS__c> listCS = new List<CS__c>();
    for(Opportunity o : trigger.new)
    {
        if(o.StageName == 'Closed/Won' && o.StageName != trigger.oldMap.get(o.Id).StageName)
        {
          //here Opportunity__c is lookup to Opportunity record for which new record is created
          listCS.add(new CS__c(Opportunity__c = o.id));
          //You canset other fields to
        }
    }
    
    if(listCS.size() > 0)
    {
        insert listCS;
    }
}

 

Ankit AroraAnkit Arora

Try this :

 

trigger CreateClass on Opportunity (after insert , before update)
{
    List<CS__c> listCS = new List<CS__c>();
    
    for(Opportunity o : trigger.new)
    {
        if(Trigger.isUpdate)
        {
            if(o.StageName == 'Closed Won' && o.StageName != trigger.oldMap.get(o.Id).StageName)
            {
              //Fill mandatory fields
              listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
            }
        }
        if(Trigger.isInsert)
        {
            if(o.StageName == 'Closed Won')
            {
              //Fill mandatory fields
              listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
            }
        }
    }

    if(listCS.size() > 0)
    {
        insert listCS;
    }
}

 There may be an instance where an opportunity have Stage equals close won. Also it is working at my end (without any syntax error and without any functionality break). Let me know if there is any problem using this.

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes

Hi this works a treat - however it creates 2 new records???

Shashikant SharmaShashikant Sharma

Which one you worked on even though second one is just the same except case of insert,

GRStevenBrookesGRStevenBrookes

tried first one but nothing happened - second one worked 'out of the box' but creates 2 CS records.

Ankit AroraAnkit Arora

No this will create only one record. Don't worry try it. I have included the conditions : Trigger.isUpdate and Trigger.isInsert.

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

Ankit AroraAnkit Arora

Are you having any workflow written on opportunity object?

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes

Ankit - I have tried it - it does work but it does create 2 records!!

Shashikant SharmaShashikant Sharma

Ok thats starnge I tested the first one and worked fine ,

Two reason why first did not work at your end

1) You directly setting it to Close/Won , and I just gave you a trigger for after update 

2) I used 'Close/Won' instead of Close Won , you can change it lke this

 

Do you have  a case where you might have stage as Close Won at insert directly.

Ankit AroraAnkit Arora

Steve, there must be any workflow on opportunity which may cause the trigger run again. Can you confirm that is there any workflow written on oppty?

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes

Hi ok - i have got both to work now - (it was the 'Closed/Won' - should be 'Closed Won') However both still creating 2 records.

 

Yes I do have workflow on opportunites. The workflow that are there must be there, is there any way of getting the apex to run after the workflow.

Ankit AroraAnkit Arora

Yes there is a workaround. I am hoping after the trigger when workflow are executed then there must be some filed update is going which again call the trigger, and it all counts in one context.

 

So to avoid the execution of trigger again after the workflow update just create this class :

 

public class myStaticClass
{
    public static boolean flag = false ;
}

 And modify your trigger like this :

 

trigger CreateClass on Opportunity (after insert , before update)
{
    if(!myStaticClass.flag)
    {
        List<CS__c> listCS = new List<CS__c>();
        
        for(Opportunity o : trigger.new)
        {
            if(Trigger.isUpdate)
            {
                if(o.StageName == 'Closed Won' && o.StageName != trigger.oldMap.get(o.Id).StageName)
                {
                  listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
                }
            }
            if(Trigger.isInsert)
            {
                if(o.StageName == 'Closed Won')
                {
                  listCS.add(new CS__c(name = 'Addendum '+ o.Name + ' Closed' , Opportunity__c = o.id));
                }
            }
        }
    
        if(listCS.size() > 0)
        {
            insert listCS;
        }
        myStaticClass.flag = true ;
    }
}

 

Thanks

Ankit Arora

 Blog | Facebook | Blog Page

This was selected as the best answer
Shashikant SharmaShashikant Sharma

Just update firstt one to this

 

trigger createNewCS on Opportunity (before update) 
{
    MAP<Id , ID> MapOpp_Cs = new MAP<ID , ID>();
    
    
    for(CS__c cs : [Select id , Opportunity__c from CS__c where Opportunity__c in: trigger.new])
    {
       MapOpp_Cs.put(cs.Opportunity__c , cs.id);
    }
    
    List<CS__c> listCS = new List<CS__c>();
    for(Opportunity o : trigger.new)
    {
        if(o.StageName == 'Closed Won' && o.StageName != trigger.oldMap.get(o.Id).StageName && (!MapOpp_Cs.containsKey(o.id)))
        {
          //here Opportunity__c is lookup to Opportunity record for which new record is created
          listCS.add(new CS__c(Opportunity__c = o.id));
          //You canset other fields to
        }
    }
    
    if(listCS.size() > 0)
    {
        insert listCS;
    }
}

 It should work for you

Shashikant SharmaShashikant Sharma

There is a flaw in this Static class solution

 

in case there is a list having items for both inser and update then static variable will be set when item for insert will come and next item will not come in the trigger , so it will fail in such case.

Ankit AroraAnkit Arora

Really ? Doesn't make sense to me as I don't think trigger get execute parallel in case of insert and update. And in both case the context is different  :)

 

Have you done this before or just expecting this behavior.

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

Shashikant SharmaShashikant Sharma

Definitly i have done this trigger execution is such that it comes again and again in the trigger once with insert items without ids then with update items

 

I have tested it out and wrote a blog as well on this

http://forceschool.blogspot.com/2011/05/writing-apex-trigger-order-of-execution.html

 

Please let me know if i am missing any thing

Ankit AroraAnkit Arora

You have discussed about "Cyclic Trigger Invocation" which is Trigger to Trigger. But in this case first trigger fired, and then workflow executes which again leads to execute the trigger. And in this case static Boolean value will work for sure.

 

Please correct me if I am wrong.

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes

Hi - didnt mean to cause an argument! Sorry.....

 

The Static option works brilliantly! Thank you very very much!

 

Can you please explain to me how the Static Class works? So I can perhaps implement this myself in the future.

Shashikant SharmaShashikant Sharma

Gr8 that worked for you,

 

And that was not an argument,  just a friendly conversation and purpose of that was just to help you and increase our knowledge as well if any of us miss any thing. Me, Ankit and others as well meet on community a lot and these conversations took place and our experience is that it has always increased our knowledge. Thats why community is the best place to learn new thing. 

TryCodingTryCoding

Hi All

 

I have a question regarding the solution of this post. Please dont mind if you find this a silly question.

 

My question is: what if we are updating the same object too in the ' after insert '  trigger? Although i know this is a bad approach. but salesforce still allows it.

 

will not the static approach affect my expected behaviour ? 

 

Regards,

TryCoding

 

 

Ankit AroraAnkit Arora

Funda of static class is very simple. When we execute a process in salesforce each property and values remain static in Static class till the process get completed. We do not need to instantiate the class to fetch its property or method, we can directly get the value with "ClassName.PropertyName".

 

As you have seen in the example provided we have a boolean property which is set to false by default when the process is started. And is set to true in the trigger. When this trigger is again called after the workflow get processed then value will remain to true as Trigger>Workflow>Trigger is executed in the same process.

 

Best is explained here :

 

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_static.htm

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes

Hi,

 

this worked fine in my sandbox - however - I have gone to deploy and get the following:

 

Test coverage of selected Apex Trigger is 0%, at least 1% test coverage is required

 

can you help?

Ankit AroraAnkit Arora

This is because you are deploying the trigger on to production without its test class. You need to create a test class this trigger and deploy both to production.

 

Please create a new thread for it, pasting your trigger code there. Some one from us will provide you the test class for it.

 

 

Thanks

Ankit Arora

Blog | Facebook | Blog Page

GRStevenBrookesGRStevenBrookes
GRStevenBrookesGRStevenBrookes

Hi - sorry to come back to this so long after the post - but as i have continued to develop our salesforce I am running into a problem - this trigger you have so kindly helped with me - which includes the StaticClass.flag works perfectly - however if i have used this trigger as a template to insert other records on the same object at the same time and the trigger dosnt trigger - i guess due to the fact that the flag is changed to true at the end of the trigger which means everything else using the flag dosnt work...which makes sense to me - however, how can I get this to work? Hope this makes sense.... 

 

Steve