You need to sign in to do that
Don't have an account?

Make a trigger work with bulk changes
Hello, I wrote my 3rd trigger in order to update the first contact of an account anytime there is a change on the account.
It seems to work properly but... not with bulk changes on accounts. Could anyone kindly have a look and give me some hints?
Thanks!
trigger UpdateFirstContactOfAccount on Account (after update) {
System.debug('UpdateFirstContactOfAccount BEGIN');
if(limitrecursion.runtwice()){
System.debug('UpdateFirstContactOfAccount RECURSIONLIMIT PASSED');
//aa
Set<Id> AccIDs = new Set<Id>();
//for(Contact con: Trigger.new) AccIDs.add(con.AccountId);
for(Account acc: Trigger.new) {
System.debug('added id to AccIDs: ' + acc.id);
AccIDs.add(acc.Id);
}
// Fetch all the Contacts for these Accounts, selecting only the oldest one of each Account
List<Contact> Cons = new List<Contact>([
select
Id, AccountId
from Contact
where AccountId = : AccIDs ORDER BY CreatedDate ASC NULLS LAST LIMIT 1
// where AccountId in : AccIDs
]);
// Build a Map, keyed by AccID, of Lists of the related Cons
Map<Id, List<Contact>> acMap = new Map<Id, List<Contact>>();
for (Contact c: Cons) {
if (acMap.containsKey(c.AccountId)) {
List<Contact> clist2;
clist2 = acMap.get(c.AccountId);
clist2.add(c);
acMap.put(c.AccountId, clist2);
} else {
System.debug('added id to acMap: acc ' + c.AccountId + ' contact ' + c.Id);
List<Contact> clist1 = new List<Contact>();
clist1.add(c);
acMap.put(c.AccountId, clist1);
}
}
List<Account> ACCS = new List<Account>();
for(Id aid: AccIDs)
{
if (acMap.containsKey(aid)) {
for (Contact cc: acMap.get(aid)) {
System.debug('Account ID' + aid + ' included');
ACCS.add(
New Account(
First_Contact__c = cc.Id ,
id=aid)
);
}
}
else
{
//remove first contact
System.debug('Account ID' + aid + ' not included');
ACCS.add(
New Account(
First_Contact__c = Null ,
Id=aid)
);
}
}
update ACCS;
}
else
{
System.debug('UpdateFirstContactOfAccount STOPPED BECAUSE OF REC LIMIT');
}
}
It seems to work properly but... not with bulk changes on accounts. Could anyone kindly have a look and give me some hints?
Thanks!
trigger UpdateFirstContactOfAccount on Account (after update) {
System.debug('UpdateFirstContactOfAccount BEGIN');
if(limitrecursion.runtwice()){
System.debug('UpdateFirstContactOfAccount RECURSIONLIMIT PASSED');
//aa
Set<Id> AccIDs = new Set<Id>();
//for(Contact con: Trigger.new) AccIDs.add(con.AccountId);
for(Account acc: Trigger.new) {
System.debug('added id to AccIDs: ' + acc.id);
AccIDs.add(acc.Id);
}
// Fetch all the Contacts for these Accounts, selecting only the oldest one of each Account
List<Contact> Cons = new List<Contact>([
select
Id, AccountId
from Contact
where AccountId = : AccIDs ORDER BY CreatedDate ASC NULLS LAST LIMIT 1
// where AccountId in : AccIDs
]);
// Build a Map, keyed by AccID, of Lists of the related Cons
Map<Id, List<Contact>> acMap = new Map<Id, List<Contact>>();
for (Contact c: Cons) {
if (acMap.containsKey(c.AccountId)) {
List<Contact> clist2;
clist2 = acMap.get(c.AccountId);
clist2.add(c);
acMap.put(c.AccountId, clist2);
} else {
System.debug('added id to acMap: acc ' + c.AccountId + ' contact ' + c.Id);
List<Contact> clist1 = new List<Contact>();
clist1.add(c);
acMap.put(c.AccountId, clist1);
}
}
List<Account> ACCS = new List<Account>();
for(Id aid: AccIDs)
{
if (acMap.containsKey(aid)) {
for (Contact cc: acMap.get(aid)) {
System.debug('Account ID' + aid + ' included');
ACCS.add(
New Account(
First_Contact__c = cc.Id ,
id=aid)
);
}
}
else
{
//remove first contact
System.debug('Account ID' + aid + ' not included');
ACCS.add(
New Account(
First_Contact__c = Null ,
Id=aid)
);
}
}
update ACCS;
}
else
{
System.debug('UpdateFirstContactOfAccount STOPPED BECAUSE OF REC LIMIT');
}
}
Hi Sebastiano,
My understanding of what you want is:
- When the first contact is created in an account, you want the account to have the "First_Contact__c" field point to that contact.
- When the first contact is deleted in an account, you want the account to have the "First_Contact__c" field point to the now oldest contact in the account.
If ths is right, the trigger you want to write is not an Account trigger, but a Contact trigger. In that trigger, have the "after insert" look at the account field First_Contact__c to see if it is null, and if so, update it with the new id. Have the "after delete" look at the account field First_Contact__c to see if it is the current record, if so, get all contacts of all accounts where this is true, sorted by account id then create date, and loop through this list to find which contact, if any, should be the new "first contact" for each account.
If you already have accounts and contacts and need to seed the initial data, I'd suggest you write a throw-away batch class to do it.
Also, it is a "best practice" to have the trigger code delegate the actual work to a class, like in the following:
Here is the trigger handler code I'd suggest:
thanks for you suggestion. I guess that you got exacthly the issue.
In fact, the trigger on the account update was designed to update all the old accounts but will not needed in the future.
>>>>>>>>you wrote<<<<<<<<
My understanding of what you want is:
1- When the first contact is created in an account, you want the account to have the "First_Contact__c" field point to that contact.
2- When the first contact is deleted in an account, you want the account to have the "First_Contact__c" field point to the now oldest contact in the account.
There is also the case in which a contact X is moved from one account A1 from another one A2. In such case I'll need to update the new account A1 (in case the contact moved is the oldest among A2 contacts) and update also the account A1 (which might remain with no contacts and First_Contact__c=null OR which might have another contact, earlier than X and oldest among the remaining ones in A1).
Thanks for your support!
I would not suggest using a trigger when you need to compute the initial data; use a batch class for that, which you can run with the System.ScheduleBatch API in the developer console.