public static void ContactFromAccount(List<Account> NewAccountList){
list<Contact> contactList = new list<contact>();
for(Account a : NewAccountList){
Account newAccount = [Select Id,Name,Phone From Account where ID = :a.id];
list<contact> newContactList = [select Phone from Contact where Phone = :newAccount.Phone]; // to check if the contact is there or not.
if(newAccount.Phone != Null && newContactList.size() == 0 ){
Contact c = new Contact();
c.AccountId = newAccount.ID;
c.Phone = newAccount.phone;
if( !newAccount.name.contains(' ')){
c.LastName = newAccount.name;
}
else{
list<string> names = newAccount.name.split(' ',2);
c.FirstName = names[0];
c.LastName = names[1];
}
contactList.add(c);
}
}
insert contactList;
}
-
6I would recommend completing Bulk Apex Triggers on Trailhead to learn the basic principles of bulkification, which is what this code needs in order to avoid this error.– David ReedCommented Jul 27, 2021 at 19:14
1 Answer
The query on Account can be moved out easily using the whole newAccountList
as WHERE clause.
Then a Set is needed to store every "free" phone number.
At first it should be filled with every phone number from the accounts, so it can be used to retrieve all Contacts at once, then the contacts' phone must be removed from the Set.
Done that, the Set will hold only the needed phone numbers, so you can loop on accounts and, only if the phone number is in the set, create the related contact.
This way there will be no query inside loops.
public static void contactFromAccount(List<Account> newAccountList) {
Set<String> phones = new Set<String>();
List<Account> accounts = [SELECT Id, Name, Phone FROM Account WHERE Id IN :newAccountList];
for (Account acc : accounts) {
phones.add(acc.Phone);
}
phones.remove(null); // we don't need to retrieve Contact without phone as we need to skip accounts without phone
for (Contact c : [SELECT Phone FROM Contact WHERE Phone IN :phones]) {
phones.remove(c.Phone);
}
// Now phones contains only phone number that are related to no contacts
List<Contact> contactToInsert = new List<Contact>();
for (Account acc : accounts) {
if (phone.contains(acc.Phone)) {
Contact c = new Contact();
c.AccountId = acc.Id;
c.Phone = acc.Phone;
if (acc.Name.contains(' ')) {
List<String> names = acc.Name.split(' ', 2);
c.FirstName = names[0];
c.LastName = names[1];
} else {
c.LastName = acc.Name;
}
contactToInsert.add(c);
// enable the next line to create at most one contact for each Phone
// phone.remove(acc.Phone);
}
}
insert contactToInsert;
}
-
+1 Mind you, this code presumes that the accounts all have different phones, etc, but this is definitely much like what I'd do.– sfdcfox ♦Commented Jul 27, 2021 at 19:46
-
@sfdcfox Since there must not be two contacts with the same phone I thought so. Anyway if accounts may share the same phone, in order to enforce the "one phone, one contact" constraint, the OP must remove the comment from
phone.remove(acc.Phone);
, this way only one contact will be created. Of course it would lead to the issue "which account should be linked to the contact?" but only the OP can know the answer, we cannot deduce it from their code.– RubenDGCommented Jul 27, 2021 at 20:28