+ Start a Discussion
Annie LaCourtAnnie LaCourt 

Getting a unique record Id in an after update trigger

I am trying to reform this trigger to remove the SOQL queries from inside the for loop. I need all the contacts for the account that is the parent of the contact record being accted on by the trigger in a list so I can test them all for the status of a set of fields. I can't figure out how to set a variable to the id of contact the trigger is acting on.   here is the codebut you really only need to look at the stuff in bold: 

rigger update_account_after on Contact (after insert, after update, after delete) {

map<Id, date> AcctNoAppeal = new map<Id, date>();
map<Id, boolean> AcctAnonymous = new map<Id,boolean>();
map<Id, boolean> AcctNoMail = new map<Id, boolean>();

boolean anon = null;
boolean nomail = null;
date noappeal = null;

//Contact cforlist = ??? I need the id of the record the trigger is acting on.  I am trying to use it to make a list of the all the contacts //related to its parent account
//List<Contact> contactlist = new List<contact>();

//IF (trigger.isupdate || trigger.isdelete){

//contactlist = [Select ID, anonymous__c, no_appeal__c, no_mail__c FROM contact where accountid = :cforlist.accountid];


for(contact c: trigger.isDelete ? trigger.Old : trigger.new){

//Account updateacc = [Select ID , anonymous__c, no_mail__c, no_appeal__c from Account where id = :c.accountid];

If (c.anonymous__c == true || c.no_mail__c != null || c.no_appeal__c != null) { 
 //if the contact is being inserted then update account according the contacts values
 If (trigger.isinsert){ 
      if (c.anonymous__c == true) AcctAnonymous.put(c.accountid, c.anonymous__c);      
      if(c.no_mail__c != null) {nomail = true;
                                AcctNoMail.put(c.accountid, nomail);
      AcctNoAppeal.put(c.accountid, c.no_appeal__c);

//the contact is being updated or deleted. iterate the contact list and set variables
//update according to the variables
If (trigger.isupdate || trigger.isdelete) {
   list<contact> contactlist = [Select ID, anonymous__c, no_appeal__c, no_mail__c FROM contact where accountid = :c.accountid];
   for(contact con :contactlist) {
        if(con.anonymous__c == true) anon = true;  
        if(con.no_mail__c != null) nomail = true;
        If (noappeal != null)  {
            if (con.no_appeal__c >= noappeal) noappeal = con.no_appeal__c;
         else if (con.no_appeal__c != null) noappeal = con.no_appeal__c;   
    IF (anon == true) AcctAnonymous.put(c.accountid,anon);
     else {anon = false; 
    IF (nomail == true) AcctNoMail.put(c.accountid, nomail);
      else {nomail = false;
            AcctNoMail.put(c.accountid, nomail);
    IF (noappeal != null) AcctNoAppeal.put(c.accountid, c.no_appeal__c);
     else {noappeal = null;
           AcctNoAppeal.put(c.accountid, c.no_appeal__c);
 }//update and delete
}//if statement     

}//for loop
    List<Account> AcctAnon = [SELECT Id, anonymous__c FROM Account WHERE Id IN :AcctAnonymous.KeySet()];
    List<Account> AcctnoMaillist = [SELECT Id, no_mail__c FROM Account WHERE Id IN :AcctNoMail.KeySet()];    
    List<Account> AcctnoAppeallist = [SELECT Id, no_appeal__c FROM Account WHERE Id IN :AcctNoAppeal.KeySet()];    
    List<Account> AccountUpdateList = new List<Account>();
    for(Account a: AcctAnon)
       a.anonymous__c = AcctAnonymous.get(a.id);
       a.anonymous__c = Anon;
       System.debug('The value is: ' + a.anonymous__c);
       System.debug('The variable is: ' + Anon);
   // for(Account a: AcctnoMaillist)
   // {
   //     a.no_mail__c = AcctNoMail.get(a);
   //     AccountUpdateList.add(a);
   // }
   // for(Account a: AcctnoAppeallist)
   // {
   //     a.no_appeal__c = AcctNoAppeal.get(a);
   //     AccountUpdateList.add(a);
   // }
   if(AccountUpdateList.size() > 0)
        update AccountUpdateList;

}//whole routine
James LoghryJames Loghry
The trigger you posted is rather messy locically speaking.  There are several conditional branches that could be simplified.  Keeping your code as simple as possible helps with reading the code, unit testing the code and maintaining it among other aspects.  To simplify the trigger, you need to:
  1. Get a set of Account Ids from the contact record(s).
  2. Query the accounts (and perhaps utilize a relationship query to get all the children contact records) based on the set of account ids.
  3. Loop through the accounts and perform your flag and date calculation logic.
I took a stab at a simplified trigger for you.  The logic in it may not be 100% correct, but should point you in the right direction.
trigger update_account_after on Contact (after insert, after update, before delete) {

    Set<Id> accountIdsToQuery = new Set<Id>();
    Map<Id,Account> accountMap = new Map<Id,Account>();

    for(Contact c : Trigger.old){

    List<Account> accts = [Select Id,(Select Id,Anonymous__c,No_Appeal__c,No_Mail__c From Contacts) From Account Where Id in :accountIdsToQuery];

    for(Account a : accts){
        boolean isAnonymous = false;
        boolean isNoMail = false;
        Date noAppeal = null;
        for(Contact c : a.Contacts){
            isAnonymous |= c.Anonymous__c;
            isNoMail |= String.isEmpty(c.No_Mail__c);
            if(c.No_Appeal__c != null && c.No_Appeal__c > noAppeal){
                noAppeal = c.No_Appeal__c;
        a.No_Mail__c = isNoMail;
        a.isAnonymous__c = isAnonymous;
        a.No_Appeal__c = noAppeal;

    update accts;

Also, when you post code or Visualforce, please use the code format (< >) button.  The button allows us to easily read your code and also copy and paste the code if necessary.
Before I can help you make this bulk ready I need a little more background about what you are trying to do.  Can you please give some background as to what this trigger is trying to solve and what each of these fields is suppose to do.
James LoghryJames Loghry
Line 20 in the code above should actually be the following:
if(c.No_Appeal__c != null && (noAppeal != null || c.No_Appeal__c > noAppeal) {

Annie LaCourtAnnie LaCourt
James, I knew the code was messy and I am hopeful that your example will help me straighten that out but perhaps I should explain what I am trying to do as pcon suggests.   I am trying to update fields on the account when a contact is updated. There are three fields: a pick list called no mail, a checkbox called anonymous and a date field called no appeal.  There are three identical similar on the account. When anonymous is checked on any contact related to an account it should ALSO be checked on the acount.  When there is a value chose for the picklist nomail on any contacts related to an account the checkbox nomail on the account should be checked.  If there is a no appeal date on any of the contacts related to an account then the account should also have a no appeal date BUT it should be whichever no appeal date on a related contact comes  last.  (yes the client is a little crazy). All of this would be doable declaratively if the account to contact relationship was master detail but its not.  

So if a new contact is created we can easily set the nomail and anonymous checkboxes on the account. And if there is a no appeal date for the new contact we just need to see if it is later or early than the date already set. easy. But if we are updating or deleting we need to look at all of the contacts related to the account of the contact being updated to figure out what to do.  

This is all happening in the NSPS so we are really dealing with households as in household accounts.  

So James, I don't need all the accounts related to a contact.  There should not be more than 1. I need all of its siblings and only if I am updating or deleting.  that said I think your code may still be doing what I want do I will test it.