+ Start a Discussion
JensenleeJensenlee 

Trigger to Update Status

Dear all,

 

I have been trying at this while pulling my hair out.

It seems simple enough, but I just cant seem to get it right.

 

I need some apex programming help on the following:

 

Will need a a trigger in custom object "Context__c" where a user insert/update/delete a new record in Context, it will effectively Inactive all older records and Active the most recent record based on Effective Date"

 

Custom object "Context__c" contains field "Status" (option of Active and Inactive) and "Effective Date"

 

Can anyone help?

 

Thanks

Jensen

Best Answer chosen by Admin (Salesforce Developers) 
Ritesh AswaneyRitesh Aswaney

DOh, it does set off in a recursive loop doesnt it - we're updating objects in an after trigger. A static variable should help

 

Declare a class, or if you've already got a Utility class, declare a static variable in it

 

static boolean contextTriggerExecuting = false;

 

then in the trigger

 

trigger changeContexttoActive on Context__c(after insert, after update)
{

if(!CLASSNAME.contextTriggerExecuting) //check that the trigger isnt already executing

{

 

CLASSNAME.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop


List<Context__c> ctxsToUpdate = new List<Context__c>{};
 
boolean firstRecord = true;
for(Context__c ctx : [Select Id, Status__c, Effective_Date__c from Context__c ORDER BY Effective_Date__c DESC])
{
if(firstRecord)
{
ctx.Status__c = True;
firstRecord = false;
}
else
ctx.Status__c = False;
 
ctxsToUpdate.add(ctx);
 
}

if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);

 

}

}

All Answers

BritishBoyinDCBritishBoyinDC

I'm curious - you want to inactivate ALL the older records in the table, or all the records linked to some other object e.g. an Account or Contact?

Ritesh AswaneyRitesh Aswaney

trigger ContextTrigger on Context__c(after insert, after update)

{

 

List<Context__c> ctxsToUpdate = new List<Context__c>{};

 

boolean firstRecord = true;

for(Context__c ctx : [Select Id, Staus__c, Effective_Date__c from Context__c ORDER BY EffectiveDate_c DESC])

{

if(firstRecord)

{

ctx.Status__c = 'Active';

firstRecord = false;

}

else

ctx.Status__c = 'Inactive';

 

ctxsToUpdate.add(ctx);

 

}

 

if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())

Database.update(ctxsToUpdate);

 

}

JensenleeJensenlee

Dear Ritesh

 

Thanks for your reply. If I tried using your code, the following messaged appearred

 

Apex trigger changeContexttoActive caused an unexpected exception, contact your administrator: changeContexttoActive: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id a0YO000000020QoMAI; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, changeContexttoActive: maximum trigger depth exceeded Context trigger event AfterUpdate for ended withTrigger.changeContexttoActive: line 21, column 1

 

Dear BritishBoyinDC


You are right, the records are linked to a master custom object "End Markets".

 

 

 

Code Used:

trigger changeContexttoActive on Context__c(after insert, after update)
{
 
List<Context__c> ctxsToUpdate = new List<Context__c>{};
 
boolean firstRecord = true;
for(Context__c ctx : [Select Id, Status__c, Effective_Date__c from Context__c ORDER BY Effective_Date__c DESC])
{
if(firstRecord)
{
ctx.Status__c = True;
firstRecord = false;
}
else
ctx.Status__c = False;
 
ctxsToUpdate.add(ctx);
 
}
if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);
}

Ritesh AswaneyRitesh Aswaney

DOh, it does set off in a recursive loop doesnt it - we're updating objects in an after trigger. A static variable should help

 

Declare a class, or if you've already got a Utility class, declare a static variable in it

 

static boolean contextTriggerExecuting = false;

 

then in the trigger

 

trigger changeContexttoActive on Context__c(after insert, after update)
{

if(!CLASSNAME.contextTriggerExecuting) //check that the trigger isnt already executing

{

 

CLASSNAME.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop


List<Context__c> ctxsToUpdate = new List<Context__c>{};
 
boolean firstRecord = true;
for(Context__c ctx : [Select Id, Status__c, Effective_Date__c from Context__c ORDER BY Effective_Date__c DESC])
{
if(firstRecord)
{
ctx.Status__c = True;
firstRecord = false;
}
else
ctx.Status__c = False;
 
ctxsToUpdate.add(ctx);
 
}

if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);

 

}

}

This was selected as the best answer
BritishBoyinDCBritishBoyinDC

And the active context record should be the most recent record for each End Markets - so if two contexts are entered, each with a different End Market, each should be marked Active, and the other Context records for each End Market should be marked as Inactive, correct?

JensenleeJensenlee

Dear BritishboyinDC

 

your are correct, there will be 1 active records for each end market...

 

Apologise for not putting out my requirements properly..

JensenleeJensenlee

I tried the following but an error appeared:

Error: Compile Error: Incompatible element type Id for collection of SOBJECT:End_Markets__c at line 8 column 1 

 

 

 

trigger changeContexttoActive on Context__c(after insert, after update)
{

List<End_Markets__c> LEM = new List <End_Markets__c>();
    for(Context__c CONTX: Trigger.new)
    {
    LEM.add(CONTX.End_Markets__c);
    }

    if(!test.contextTriggerExecuting) //check that the trigger isnt already executing
        {
    test.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop


List<Context__c> ctxsToUpdate = new List<Context__c>{};

boolean firstRecord = true;

for(Context__c ctx : [Select Id, Status__c, Effective_Date__c from Context__c where End_Markets__c =: LEM ORDER BY Effective_Date__c DESC])
{
if(firstRecord)
{
ctx.Status__c = True;
firstRecord = false;
}
else
ctx.Status__c = False;
 
ctxsToUpdate.add(ctx);
 
}
if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);
 
}
}

Rahul S.ax961Rahul S.ax961

Hello Jen,

 

I dint understand much, but i'll give a try to help.

Here, I assume Context is child object of End_Markets.

 

Then, instead writing trigger Context, write trigger on Parent object (End_Markets).

I modified your code to some extent, Hope it helps.

 

/*-----------------------------------------------------------Start-----------------------------------------------------------------*/

trigger changeContexttoActive on End_Markets__c(after insert, after update)
{
    Set<Id> LEMId = new Set<Id>();
    for(End_Markets__c objEM: Trigger.new)
    {
        LEMId.add(objEM.Id);
    }
    if(!test.contextTriggerExecuting) //check that the trigger isnt already executing
    {
        test.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop
        List<Context__c> ctxsToUpdate = new List<Context__c>([Select Id, Status__c, Effective_Date__c from Context__c where End_Markets__c =: objEM ORDER BY Effective_Date__c DESC]);
        for(Integer i = 0; i < ctxsToUpdate.size(); i++)
        {
            if(i=0)
                ctxsToUpdate.Status__c = True;
            else
                ctxsToUpdate.Status__c = False;
        }
        if(!ctxsToUpdate.IsEmpty())
            update ctxsToUpdate;
    }
}

/*-----------------------------------------------------------End-----------------------------------------------------------------*/

 

Thanks & regards,

Rahul Sharma

BritishBoyinDCBritishBoyinDC

Based on your feedback I am pretty sure this is what you want - the trigger basically uses a nested query to pull back all the context records for any End Market that needs to be updated based on a new Context being added/updated/delete, sets the first one retrieved to active since that is the most recent date, and the others to inactive if they aren't already inactive...you may need to change the SOQL if it doesn't compile to use the correct relationship name...

 

 

trigger changeContexttoActive on Context__c(after insert, after update, after delete) {

if(!test.contextTriggerExecuting) { //check that the trigger isnt already executing
    test.contextTriggerExecuting = true;  //set trigger executed = true

Set<Id> emtoupdate = new Set<Id> ();

if (Trigger.isInsert || Trigger.isUpdate ) {
for (Context__c c: Trigger.New) {
emtoupdate.add(c.End_Markets__c);
}
}


if (Trigger.isDelete) {
for (Context__c c: Trigger.Old) {
emtoupdate.add(c.End_Markets__c);
}
}


List<Context__c> contoupdate = new List<Context__c>();

List<End_Markets__c> LEM = [Select Id, Name, (Select Id, End_Markets__c, Status__c, Effective_Date__c From Context__r order by Effective_Date__c desc) From End_Markets__c];

for (End_Markets__c em: LEM) {
if (em.Context__r.size() > 0) {
List<Context__c> ucontext = em.Context__r;

for (Integer i = 0; i < ucontext.size(); i++ )

if ( i == 0 ) {
        //only process if not currently active record
        if ( ucontext[i].Status__c != TRUE) {
        ucontext[i].Status__c = TRUE;
        contoupdate.add(ucontext[i]);
        
        }
}
else {
//only process if record is currently active, and needs to be inactivated
        if ( ucontext[i].Status__c == TRUE) {
        ucontext[i].Status__c = FALSE;
        contoupdate.add(ucontext[i]);
       }
}
}
} 

try {
Database.update(contoupdate); 
}
Catch (Exception Ex) {
system.debug(Ex);
}
 
}
} //end trigger

 

 

 

 

JensenleeJensenlee

Dear all,

 

Below is now the working code that I have used.

I have tested using bulk uploads and works like a charm..

 

Sources: I have used a combination of Ritesh Aswaney / BritishBoyinDC

 

Really appreciate the contributions within the salesforce community - I can only hope that I can pick up the language soon!

 

 

trigger changeContexttoActive on Context__c(after insert, after update) {

    if(!test.contextTriggerExecuting){ //check that the trigger isnt already executing
    test.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop

Set<Id> emtoupdate = new Set<Id> ();

if (Trigger.isInsert || Trigger.isUpdate ) {
for (Context__c c: Trigger.New) {
emtoupdate.add(c.End_Markets__c);
}
}

if (Trigger.isDelete) {
for (Context__c c: Trigger.Old) {
emtoupdate.add(c.End_Markets__c);
}
}

List<Context__c> ctxsToUpdate = new List<Context__c>{};

boolean firstRecord = true;

for(Context__c ctx : [Select Id, Status__c, Effective_Date__c from Context__c where End_Markets__c =: emtoupdate ORDER BY Effective_Date__c DESC])
{
if(firstRecord)
{
ctx.Status__c = True;
firstRecord = false;
}
else
ctx.Status__c = False;
 
ctxsToUpdate.add(ctx);
 
}
if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);
 
}
}

Hilary EngelbrechtHilary Engelbrecht
Hello,

I recently came across this. While useful, I've modified the code posted above that the previoius poster said they used to account for my parent, child objects and related fields.

I am receiving the following error: Error: Compile Error: Variable does not exist: contextTriggerExecuting at line 3 column 14.

Anyone know what I am missing?
trigger changeContexttoActive on FGM_Base__Grantee_Report__c(after insert, after update) {

    if(!test.contextTriggerExecuting){ //check that the trigger isnt already executing
    test.contextTriggerExecuting = true;  //set to true so it doesnt go in a recursive loop

Set<Id> emtoupdate = new Set<Id> ();

if (Trigger.isInsert || Trigger.isUpdate ) {
for (FGM_Base__Grantee_Report__c c: Trigger.New) {
emtoupdate.add(c.Opportunity);
}
}

if (Trigger.isDelete) {
for (FGM_Base__Grantee_Report__c c: Trigger.Old) {
emtoupdate.add(c.Opportunity);
}
}

List<FGM_Base__Grantee_Report__c> ctxsToUpdate = new List<FGM_Base__Grantee_Report__c>{};

boolean firstRecord = true;

for(FGM_Base__Grantee_Report__c ctx : [Select Id, Most_Recent_Report__c, FGM_Base__Submission_Date__c from FGM_Base__Grantee_Report__c where Opportunity =: emtoupdate ORDER BY FGM_Base__Submission_Date__c DESC])
{
if(firstRecord)
{
ctx.Most_Recent_Report__c = True;
firstRecord = false;
}
else
ctx.Most_Recent_Report__c = False;
 
ctxsToUpdate.add(ctx);
 
}
if(ctxsToUpdate != null && !ctxsToUpdate.IsEmpty())
Database.update(ctxsToUpdate);
 
}
}