Salesforce Asked by AKor on October 4, 2021
So I’m trying to associate new contacts and cases with an account automatically. I’ve been creating contacts and cases without an account using an automated script. I understand that at this point, I have to use an APEX trigger although the use case is very simple.
I’m very new to APEX triggers, so I didn’t get any further than the logic.
trigger associateWithAccount on Contact (before insert) {
//get Company__c from Contact
//lookup Accounts by Account Name using Company__c
//get AccountID from the result of that lookup
//insert AccountID from Account into AccountID in Contact
Map<String, String> extMap = new Map<String, String>();
Set<String> extIdSet = new Set<String>();
for(Contact c : Trigger.new){
extIdSet.add(c.Company__c);
}
for(Account a : [select Id, Name from Account where Name IN :extIdSet]){
extMap.put(a.Id, a.Name);
}
for(Contact c : Trigger.new){
c.Account = extMap.get(c.Id);
}
}
However, I keep getting the error that I am illegally assigning from String to Account. Any help?
Let's rewrite this with some better variable names while recognizing that Contacts if created from the UI will most likely have their AccountId already populated
trigger associateWithAccount on Contact (before insert) {
Map<String, Account[]> accountsByCompanyName; // could be more than one Account w/ same name
Set<String> searchCompanyNames = new Set<String>();
// Step 1 - gather search keys
for(Contact c : Trigger.new){
if (c.AccountId == null && String.isNotBlank(c.Company__c)) {
searchCompanyNames.add(c.Company__c);
}
}
// Step 2 - find Accounts by contact.Company__c
accountsByCompanyName = Util.pivotSObjectsByString(Account.Name,
[Select Id, Name From Account Where Name IN :searchCompanyNames]);
// Step 3 - Associate Contact in trigger.new to Account
for(Contact c : Trigger.new){
if (c.AccountId != null) {continue;} // nothing to do
Account[] matchingAccounts = accountsByCompanyName.get(c.Company__c);
if (matchingAccounts.isEmpty()) {continue;} // no match
if (matchingAccounts.size() > 1) {continue;} // ambiguous - do nothing
c.AccountId = matchingAccounts[0].Id; // unambiguous match
}
}
And handy Util methods (there are other, better flavors of this like SObjectIndex in GitHub)
public static map<String,List<SObject>> pivotSObjectsByString(Schema.SObjectField fldToken, SObject[] sobjList) {
map<String,List<SObject>> res = new map<String,List<SObject>> ();
for (Sobject sobj: sobjList == null ? new list<Sobject>() : sobjlist) {
String pivotKey = (String) sobj.get(fldToken);
if (res.containsKey(pivotKey)) {
res.get(pivotKey).add(sobj);
}
else {
Sobject[] typedSobjs = makeTypedSobjList(sobj); // do this so resulting list.getSobjectType() doesn't return null
typedSobjs.add(sobj);
res.put(pivotKey,typedSobjs);
}
}
return res;
}
public static Sobject[] makeTypedSobjList(Sobject sobj) {
return (Sobject[]) Type.forName('List<'+sobj.getSObjectType()+'>').newInstance();
}
Answered by cropredy on October 4, 2021
Welcome to the wonderful world of Apex! A couple of points:
Typically if we want to fill in data on a record when it's being added into the system, we want to do this in the "Before" stage. Otherwise, we're performing essentially 2 operations for every record, which isn't very safe.
Your overall order of operations is right on the money, though!
Here is a trigger example from stack-exchange that is doing essentially the same thing : How to use External Ids in a Before Insert trigger? . Check out the accepted answer there :-)
Answered by Adam Michael Daw on October 4, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP