You need to sign in to do that
Don't have an account?
Jensenlee
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
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
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?
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);
}
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);
}
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);
}
}
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?
Dear BritishboyinDC
your are correct, there will be 1 active records for each end market...
Apologise for not putting out my requirements properly..
I tried the following but an error appeared:
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);
}
}
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
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...
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);
}
}
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?