Preface: this post is part of the SFDC99 Challenges series.
Can you find everything wrong with this trigger?
Fix this trigger, paste it in the comments, and see how you do!
Note that you’ll need to read up until at least Chapter 5 to solve this. Good practice bulkifying!
// Automatically populate a lookup field to the Rival object trigger GetRival on Account (after insert, after update) { for (Account acc : Trigger.new) { // Find the Rival record based on the picklist valueRival__c comp = [SELECT Id, Name FROM Rival__c WHERE Name = acc.Rival_Picklist__c];// Rival__c is a lookup to the Rival custom object acc.Rival__c = comp.Name; } }
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
System.debug(‘Account get Rival’);
Set accRivalpicklist = new Set();
Map compName = new Map();
List Accounts = new List();
for (Account acc : Trigger.new) {
if(acc.Rival_Picklist__c!=null){
accRivalpicklist.add(acc.Rival_Picklist__c);
Accounts.add(acc);
}
}
// Find the Rival record based on the picklist value
for(Rival__c comp : [SELECT Id, Name
FROM Rival__c
WHERE Name in :accRivalpicklist]){
compName.put(comp.name,comp.ID);
}
for(Account acc :Accounts ) {
// Rival__c is a lookup to the Rival custom object
if(compName.get(acc.Rival_Picklist__c)!=null){
acc.Rival__c = compName.get(acc.Rival_Picklist__c);
}
}
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (after insert, after update) {
if(Trigger.isAfter){
Set rivelName = pluck.strings(“Rival_Picklist__c”,Trigger.New);
Rival__c accRivalName = [SELECT Id, Name
FROM Rival__c
WHERE Name = acc.Rival_Picklist__c];
for(Account acc : Trigger.New){
acc.Rival__c = accRivalName.Name;
}
}
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
Map<String, List> map_AccountPicklist = new Map<String, List>();
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
List list_Accounts = new List();
if(map_AccountPicklist.contains(acc.Rival_Picklist__c))
list_Accounts = map_AccountPicklist.get(acc.Rival_Picklist__c);
list_Accounts.add(acc);
map_AccountPicklist.put(acc.Rival_Picklist__c, list_Accounts);
}
Map map_RivalNamesToId = new Map();
for(Rival__c objRival : [SELECT Id, Name FROM Rival__c WHERE Name IN: map_AccountPicklist.keySet()]) {
map_RivalNamesToId.put(objRival.Name, objRival.Id);
}
for(String strPickVal : map_AccountPicklist.keySet()) {
// Rival__c is a lookup to the Rival custom object
for(Account objAcct : map_AccountPicklist.get(strPickVal)) {
objAcct.Rival__c = map_RivalNamesToId.get(strPickVal);
}
}
}
Wow, man was I out of it when I wrote that. Updated:
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
Map<String, List> map_AccountPicklist = new Map<String, List>();
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
List list_Accounts = new List();
if(map_AccountPicklist.containsKey(acc.Rival_Picklist__c))
list_Accounts = map_AccountPicklist.get(acc.Rival_Picklist__c);
list_Accounts.add(acc);
map_AccountPicklist.put(acc.Rival_Picklist__c, list_Accounts);
}
Map map_RivalNamesToId = new Map();
for(Rival__c objRival : [SELECT Id, Name FROM Rival__c WHERE Name IN: map_AccountPicklist.keySet()]) {
map_RivalNamesToId.put(objRival.Name, objRival.Id);
}
for(String strPickVal : map_AccountPicklist.keySet()) {
// Rival__c is a lookup to the Rival custom object
for(Account objAcct : map_AccountPicklist.get(strPickVal)) {
objAcct.Rival__c = map_RivalNamesToId.get(strPickVal);
}
}
}
This trigger does the trick for me
trigger GetRival on Account (before insert, before update) {
Rival__c r = [SELECT Id, Name FROM Rival__c];
for(Account a : Trigger.New) {
if(r.Name == a.Rival_Picklist__c) {
a.Rival__c = r.Id;
}
}
}
Trigger getRival on Account(After insert,After update, before insert, before update){
Map accountperRivalpicklist = new Map();
for(Account acc : trigger.new){
accountperRivalpicklist.put(acc.rival_picklist__c,acc);
}
List rivalstobeupdated = new List();
for(Rival__c rival : [SELECT Id,Name from Rival__c where NAME IN: accountperRivalpicklist.put.keyset()]){
if(accountperRivalpicklist.put.keyset().contains(rival.Name)){
rival.Account__c = accountperRivalpicklist.put.keyset.get(rival.Name).Id;
rivalstobeupdated.add(rival);
}
}
if(!rivalstobeupdated.isEmpty()){
update rivalstobeupdated;
}
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
Set rivalName = new set();
for (Account acc : Trigger.new) {
rivalName.add(acc.Rival_Picklist__c);
}
//Build rival name, id map
Map rivalMap= new Map();
for(Rival__c rivalObject : [SELECT id, Name FROM Rival__c WHERE Name : rivalName]) {
rivalMap.put(rivalObject.Name, rivalObject.Id);
}
for (Account acc : Trigger.new) {
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = rivalMap.get(acc.Rival_Picklist__c);
}
}
// First thing for update same object we need to write trigger using before event
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
Map rivalCustomMap = new Map();
List rivalStringList = new List();
for (Account acc : Trigger.new) {
rivalStringList.add(acc.Rival_Picklist__c);
}
List rivalList = [SELECT Id, Name
FROM Rival__c
WHERE Name IN :rivalStringList
];
for(Rival__c rival : rivalList){
rivalCustomMap.put(rival.Name, rival.Id);
}
for (Account acc : Trigger.new) {
acc.Rival__c = rivalCustomMap.get(acc.Rival_Picklist__c);
}
}
trigger GetRival on Account (before insert, before update) {
Set setAccRival = new Set();
for(Account acc : Trigger.new){
setAccRival.add(setAccRival);
}
Map mapAccIdRival = new Map[[SELECT AccountId, Name
FROM Rival__c WHERE Name IN:setAccRival];
for (Account acc : Trigger.new) {
acc.Rival__c = mapAccIdRival.get(acc.Id).Name;
}
}
}
trigger GetRival on Account (before insert, before update) {
Set r = new Set();
for (Account acc : Trigger.new) {
r.add(acc.Rival_Picklist__c);
}
List rList = new List([select Id, name from Rival__c where id in :r);
Map rMap = new Map();
for (Rival__c rr : rList){
rMap.put(rr.Id, rr);
}
for ( Account acc : Trigger.New){
Rival rRec = rMap.get(acc.Rival_Picklist__c) ;
acc.Rival__c = rRec.name;
}
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (after insert, after update) {
List updatedRivalAccounts = List();
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
try{
Rival__c comp = [SELECT Id, Name
FROM Rival__c
WHERE Name = acc.Rival_Picklist__c];
}catch(Exception ee){
System.debug(ee);
}
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = comp.Id;
updatedRivalAccounts.add(acc);
}
update updatedRivalAccounts;
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
List comp = [SELECT Id, Name
FROM Rival__c
WHERE Name = acc.Rival_Picklist__c limit 1];
String rivalId=null;
if(comp !=null && comp.size()>0)
rivalId= comp.get(0).id;
for (Account acc : Trigger.new) {
acc.Rival__c = rivalId;
}
}
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
Rival__c comp = [SELECT Id,Name FROM Rival__c WHERE Name = :acc.Rival_Picklist__c];
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = comp.id;
}
}
trigger GetRival on Account (before insert, before update) {
//Create a set of rival picklist values
set rivalPickList = new Set();
for (Account acc : Trigger.new) {
rivalPickList.add(a.rival_picklist__c);
}
List rivalObjList = [Select Id,Name from Rival__c where Name in: rivalPickList];
Map rivalNametoIdMap = new Map();
//Create a map to search
for(Rival__c r:rivalObjList) {
rivalNametoIdMap.put(r.Name, r.Id);
}
//Associate the account record with Rival object
for(Account acc:Trigger.New) {
Id rivalId = rivalNametoIdMap.get(a.rival_picklist__c);
acc.Rival__c = rivalId;
}
}
//bulkify the code
trigger GetRival on Account (before insert, before update) {
//gathering all Rival picklists in set collection
Set searchterm = new Set();
for (Account newacc : Trigger.new) {
searchterm.add(newacc.Rival_picklist__c);
}
//Searching for Rival records against my set data collection
List searchresult = [SELECT Id, Name FROM Rival__c WHERE Name IN :searchterm];
//Mapping all records to retrieve specific result corresponds to the account rival picklist
Map finalrivals = new Map();
for (Rival__c maprivals : searchresult) {
finalrivals.put(maprivals.Name, maprivals);
}
//Each account is populating with its respective rival lookups
//For record insertion
if (Trigger.isbefore) {
if (Trigger.isinsert) {
for (Account newacc : Trigger.new) {
if (newacc.Rival_Picklist__c != null) {
Rival__c rivalinclusionacc = finalrivals.get(newacc.Rival_Picklist__c);
newacc.Rival__c = rivalinclusionacc.Id;
}
}
}
}
//For record update with oldMap method
if (Trigger.isbefore) {
if (Trigger.isupdate) {
for (Account newacc : Trigger.new) {
if (Trigger.oldMap.get(newacc.Id).Rival_Picklist__c != newacc.Rival_Picklist__c) {
Rival__c rivalinclusionacc = finalrivals.get(newacc.Rival_Picklist__c);
newacc.Rival__c = rivalinclusionacc.Id;
}
}
}
}
}
trigger GetRival on Account (before insert, before update) {
Map acctToRival = new Map();
for (Rival__c riv : [SELECT Id, Name FROM Rival__c]) {
acctToRival.put(riv.Name, riv.Id);
}
for(Account a : Trigger.new) {
a.Rival__c = acctToRival.get(a.Rival_Picklist__c);
}
}
Thank you for all your blogs. They are a great deal for students like me. Below is my code for the given challenge. Please let me know about my mistakes or anything that I can improve in this solution. Thanks again.
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
Set accountRivalsPickVals = new List();
Map rivalNameToIdMap = new Map();
// Get the all the picklist values from new Accounts (Bulkification)
for(Account acc : Trigger.new)
{
accountRivalsPickVals.add(acc.Rival_Picklist__c);
}
// Single SOQL to query all the rival records that are in the account picklist field (avoid 101 SOQL)
List rivalRecords = [Select Id, Name From Rival__c Where Name in : accountRivalsPickVals];
// Create a map of name to Id for all the extracted rival records
//(reduce time complexity by avoiding for nested loop)
for(Rival__c rivalRec : rivalRecords)
{
rivalNameToIdMap.put(rivalRec.Name, rivalRec.Id);
}
// If account is inserted update the rival field
if(Trigger.isInsert)
{
for(Account newAcc : Trigger.new)
{
newAcc.Rival__c = rivalNameToIdMap.get(newAcc.Rival_Picklist__c);
}
}
// if already existing account is updated
if(Trigger.isUpdate)
{
for(Account newAcc : Trigger.new)
{
String oldRivalPickValue = Trigger.oldMap.get(newAcc.Id).Rival_Picklist__c;
if(!newAcc.Rival_Picklist__c.equals(oldRivalPickValue)) // check if rival pick val is updated
newAcc.Rival__c = rivalNameToIdMap.get(newAcc.Rival_Picklist__c);
}
}
}
Hi David,
first of all thanks for all the efforts you are doing to provide this site to the community. I am very thankful I found this site. It helps me a lot on my way becoming a Salesforce developer. I hope there will be one time the chance to meet, shake hands and thank you personally.
Here is my trigger:
trigger GetRival on Account (before insert, before update) {
Set rivalNames = new Set();
for(Account acc : Trigger.new) {
rivalNames.add(acc.Rival_Picklist__c);
}
List accts2update = new List();
Map RivalName2RivalMap = new Map();
List comps = [Select Id, Name From Rival__c
Where Name IN: rivalNames];
for(Rival__c comp : comps) {
RivalName2RivalMap.put(comp.Name,comp.Id);
}
if(RivalName2RivalMap != null) {
for(Account a : Trigger.new) {
a.Rival__c = RivalName2RivalMap.get(a.Rival_Picklist__c);
}
}
}
All the best!
Michael
Thank you for the kind words Michael!
trigger GetRival on Account (before insert, before update)
{
for(Account acc: trigger.New)
{
string s= acc.Rival_picklist__c;
Rival__c riv= [select Id, Name from Rival__c where Name=:s];
acc.Rival__c=riv.Id;
}
}
trigger GetRival on Account (before insert, before update) {
map rivalMap = new map();
set rivalSet = new set();
for(Account acc : Trigger.new){
rivalSet.add(acc.Rival_Picklist__c);
}
list rivalLst = new list();
rivalLst = [SELECT Id, Name
FROM Rival__c
WHERE Name IN: rivalSet];
for(Rival__c rivalObj : rivalLst){
rivalMap.put(rivalObj.Name, rivalObj.Id);
}
for(Account acc : Trigger.new){
acc.Rival__c = rivalMap.get(acc.Rival_Picklist__c);
}
}
Please let me know if there are any issues here.
trigger GetRival on Account (before insert, before update) {
List comps = [SELECT Id, Name
FROM Rival__c
WHERE Name = acc.Rival_Picklist__c];
Map rivalMap = new Map();
for(Rival_c comp : comps){
rivalMap.put(comp.Id , comp);
}
for (Account acc : Trigger.new) {
Rival_c comp = rivalMap.get(acc.Id);
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = comp.Id
}
}
Hello,
I figured out this solution.
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (after insert, after update) {
// 1. Create a map Rival Id >
Map nomeRivIdMap = new Map();
for(Rival__c r: [SELECT Id, Name FROM Rival__c]){
nomeRivIdMap.put(r.name, r.id);
}
// 2. Match the accounts by the rival, according to the picklist value.
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
String picklistVal = acc.Rival_Picklist__c;
Id RivalId = nomeRivIdMap.get(picklistVal);
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = RivalId;
}
}
Cheers,
E.
*Just a small edit:
Before actually writing the lookup value at the account, we should check
if there exists a rival record for this picklist value.
A simple:
if(String.isBlank(RivalId){
continue;
}
before the lookup writing, will do the work.
trigger GetRival on Account (before insert, before update){
Set rivalPicklistSet = new Set();
Map rivalMap = new Map();
Set foundRivalSet = new Set();
for(Account acc : Trigger.new){
rivalPicklistSet.add(acc.Rival_Picklist__c);
}
if(!rivalPicklistSet.isEmpty()){
for(Rival__c rival : [SELECT Id, Name FROM Rival__c WHERE Name IN : rivalPicklistSet]){
rivalMap.put(rival.Name,rival.Id)
foundRivalSet.add(rival.Name);
}
}
if(!rivalMap.isEmpty()){
for(Account acc : Trigger.new){
if(foundRivalSet.contains(acc.Rival_Picklist__c)){
acc.Rival__c = rivalMap.get(acc.Rival_Picklist__c);
}
}
}
}
Hello,
I have just started learning SF (about 3 weeks now!!) and below is my version of the solution:
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
List acc = new List();
List rivalAcc = [SELECT Id, Name FROM Rival__c WHERE Name = :acc.Rival_Picklist__c];
Map accnRivals = new Map();
for(Rival__c rivalInLoop : rivalAcc) {
accnRivals.put(acc.Id,rivalAcc.Name);
}
for(Account accInTrigger : trigger.new) {
accInTrigger.Rival_Picklist__c = accnRivals.get(accInTrigger.Id);
}
}
Please do let me know in case there are any issues. I havent tried this in my Dev org. Just came up with it by reading till Chapter 5!
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (after insert, after update) {
for (Account acc : Trigger.new) {
// Find the Rival record based on the picklist value
Rival__c comp = [SELECT Id, Name //Error 1 – Rival__C is a field and it cannot be a DataType.
FROM Rival__c
WHERE Name = acc.Rival_Picklist__c]; //Error 2: there should be a ‘:’ after ‘=’ as acc is a variable
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = comp.Name;
//Error 3: This single step won’t update we need to first add this ‘acc’ to a list of Account. then update that list outside for loop.
}
}
trigger GetRival on Account (before insert,before update) {
Set rivalSet= new Set();
List rivalList = new List();
for(Id key:Trigger.newMap.keySet())
rivalSet.add(Trigger.newMap.get(key).Rival_Picklist__c);
rivalList = [SELECT Id,Name FROM Rival__c WHERE Name IN: rivalSet];
for(Account a:Trigger.new){
if(a.Rival_Picklist__c!=null){
for(Rival__c r:rivalList ){
if(a.Rival_Picklist__c==r.Name)
a.Rival__c=r.Name;
}
}
}
}
Trigger
================
trigger GetRivalonAccount on Account (before insert,before update) {
Set rivalSet = new Set();
for (Account acc: Trigger.new){
if(acc.Rival_Picklist__c != null){
rivalSet.add(acc.Rival_Picklist__c);
}
}
List rivalList = [SELECT Id,Name FROM Rival__c WHERE Name IN: rivalSet];
Map rivalMap = new Map();
for(Rival__c riv:rivalList){
rivalMap.put(riv.Name,riv.Id);
}
for(Account acc: Trigger.new){
if(acc.Rival_Picklist__c != null){
acc.Rival__c = rivalMap.get(acc.Rival_Picklist__c);
}
}
}
Test Class..
===============
@isTest
public class TestGetRivalValue {
static testMethod void TestGetRivalValuemthd(){
Rival__c riv = new Rival__c();
riv.Name = ‘Best’;
insert riv;
Account acc1 = new Account();
acc1.Name= ‘test rivalss’;
acc1.Rival_Picklist__c =’Best’;
acc1.rival__c = riv.Id; // Relationship Id
insert acc1;
List accs = new List();
for (Integer i=0;i<200;i++){
Account acc= new Account();
acc.Name= 'test rivalss';
acc.Rival_Picklist__c ='Best';
acc.Rival__c =riv.Id; // Relationship FIELD
accs.add(acc);
}
insert accs;
List newaccs = new List();
newaccs = [SELECT Id, Rival_Picklist__c, Rival__r.Name FROM Account];
for (Account a:newaccs){
System.assertEquals(a.Rival__r.Name,a.Rival__c);
}
}
}
trigger GetRival on Account (after insert, after update)
{
Map accIdRivalName = new Map();
for(Account acc : Trigger.new)
{
accIdRivalName.add(acc.Id,acc.Rival_Picklist__c);
}
List comp = [SELECT Id, Name
FROM Rival__c
WHERE Name in :accIdRivalName.values()];
for(Account acc:comp)
{
acc.Rival__c = accIdRivalName.get(acc.Id);
}
}
Jaya , this shud be a before insert , before update trigger if running on the account object – as a record is in read only in an after insert . Secondly the last For loop on the Account should iterate across Trigger.new rather than comp as there is no relationship currently between Rival_c (List Comp) and Account and the relationship gets established only after the Lookup field in Account viz Rival__c is populated with value of Name from the object Rival__c. An after insert ,after update trigger can run on Rival__c object instead to give the same result.
trigger GetRival on Account (before insert,before update) {
//while inserting Account get the Rival picklist values
Set accRivalSet = new Set();
for(Account a: Trigger.new){
accRivalSet.add(a.Rival_Picklist__c);
}
//get the picklist values from rival that Account has
List rivalList=[select id,name from Rival__c where name in :accRivalSet];
maprivalPicklistMap = new map();
for (Rival__c r: rivalList){
//feed the map
rivalPicklistMap.put(r.name,r);
}
for(Account a : Trigger.new){
//populate rival values
if(rivalPicklistMap.containskey(a.Rival_Picklist__c)){
//fill lookup rival
a.Rival__c= rivalPicklistMap.get(a.Rival_Picklist__c).id;
}
}
}
//— Changed the Trigger Name to be more Descriptive
trigger PopulateAccountRival on Account (before insert, before update) {
//— Created a Map to store all Rival values along with their Ids, removed the SOQL from within the FOR statement
Map rivalMap = new Map();
List rivalList = [select Id, Name from Rival__c];
for(Rival__c rival : rivalList)
rivalMap.put(rival.Name, rival.Id);
for (Account acc : Trigger.new) {
acc.RivalId__c = rivalMap.get(acc.Rival_Picklist__c);
}
}
trigger GetRival on Account (before insert, before update) {
Set myRivals = new Set();
for (Account accountRivals: Trigger.new) {
if(accountRivals.Rival_Picklist__c !=null){
myRivals.add(accountRivals.Rival_Picklist__c);
}
List myOwnRivals = [Select Id, Name From Rival__c
Where Name In :myRivals];
Map rivalsMap = new Map();
for (Rival__c u : myOwnRivals){
rivalsMap.put (u.Name, u);
}
for (Account newRivalName : trigger.new) {
if (accountRivals.Rival_Picklist__c != null){
Rival__c theTrueRival = rivalsMap.get(accountRivals.Rival_Picklist__c);
if(theTrueRival != null){
newRivalName.Rival__c = theTrueRival.id;
}
}
}
}
}
Lookup fields apparently like Id’s, and not strings. The error “Invalid id: Rival 1” prompted me to change “theTrueRival.name” to “theTrueRival.id”, then it worked just fine.
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger GetRival caused an unexpected exception, contact your administrator: GetRival: execution of BeforeUpdate caused by: System.StringException: Invalid id: Rival 1: Trigger.GetRival: line 19, column 1
Cheers
trigger getRival on Account (before insert, before update)
{
Map nameListmap = new Map();
List rivList = [select id,name from rival__c];
for(Rival__c ri : rivList)
{
nameListmap.put(ri.name,ri.id);
}
for(Account acc : trigger.new)
{
if(nameListmap.containsKey(acc.Rival_picklist__c))
acc.Rival__c = nameListMap.get(acc.Rival_picklist__c);
}
}
Hey David n everyone…
Please validate my trigger.. whether it will work?
trigger getRival on Account(before insert, beofre update){
set RivalName = new set();
for(Account acc: Trigger.new){
RivalName.add(acc.Rival_pickList__c);
}
List RivalObj = [select Id, name from Rival__c where name=: RivalName];
Map RivalMap= new map();
for(Rival__c riv : RivalObj){
RivalMap.put(riv.name, riv);
}
for(Account acc2: Trigger.new){
if(acc2.Rival_PickList__c!=null){
acc2.Rival__c = RivalMap.get(Rival_PickList__c);
}
}
}
You can test it out in your org too!
Hard to tell just by reading it =)
David
Problems
1) The overall design could be better. For one, a company typically has one or more
rivals so the Rival custom object should be a junction object with 2 account
lookups. Rivals would then be tied to other accounts. With rival records for each account,
then each account would have a list of rivals. This requires no apex trigger to synchronize
the account lookup based on the selected rival picklist value and allows other rival attributes
to be tracked if needed.
2) Before Insert and Before update should be used since setting the Rival
lookup won’t actually update anything since “after insert” and “after update”
are used.
3) The list of rivals should be queried once with all the possible rivals being used
in the inserted or updated accounts.
4) If the Rival Picklist doesn’t have a value, errors will be thrown.
5) If the rival is updated to blank, the rival lookup isn’t cleared.
6) The soql query is missing the colon.
7) Trigger Name implies that one Account trigger is created for each Account feature.
Ideally, one account trigger is created and, this is more of taste, should
delegate to a helper apex class such as a “Trigger Handler”.
Solution
trigger AccountTrigger on Account (before insert, before update){
if (Trigger.isBefore){
if (Trigger.IsInsert){
AccountTriggerHandler.setRivalOnInsert(Trigger.new);
}
else if (Trigger.IsUpdate){
AccountTriggerHandler.setRivalOnUpdate(Trigger.oldMap, Trigger.newMap);
}
}
}
public class AccountTriggerHandler {
public static void setRivalOnInsert(List newAccounts){
List newAccountsWithRival = new List();
for (Account newAcct : newAccounts){
if (String.isBlank( newAcct.Rival_Picklist__c ) == false){
rivalNames.add( newAcct.Rival_Picklist__c );
newAccountsWithRival.add(newAcct);
}
}
// Only sync when necessary.
if (rivalNames.size() > 0){
syncRivalsOnAccounts(newAccountsWithRivals);
}
}
public static void setRivalOnUpdate(Map oldAccounts, Map newAccounts){
List updatedAccountRivals = new List();
for (Account newAcct : newAccounts){
Account oldAcct = oldAccounts.get(newAcct.Id);
// Rival didn’t change so nothing to do so continue on.
if (oldAcct.Rival__c == newAcct.Rival__c){
continue;
}
if (String.isBlank( newAcct.Rival_Picklist__c )){
newAcct.Rival__c = null;
}
else {
updatedAccountRivals.add(newAcct);
}
}
// Only sync when necessary.
if (updatedAccountRivals.size() > 0){
syncRivalsOnAccounts(updatedAccountRivals);
}
}
private static void syncRivalsOnAccounts(List accountsWithRivals){
Set rivalNames = new Set();
// Only query the rivals that we need.
for (Rival__c accountWithRival : accountsWithRivals){
rivalNames.add(accountWithRival.Rival_Picklist__c);
}
Map rivalAccountsMap = getRivalAccountsMap(rivalNames);
for (Account newAccountWithRival : newAccountsWithRival){
Rival__c rival = rivalAccountsMap.get(newAccountsWithRival.Rival_Picklist__c);
// Ensure the rival exists
if (rival != null){
newAccountWithRival.Rival__c = rival.Id;
}
}
}
private static Map getRivalAccountsMap(String rivalNames){
List rivals =
[select Id,
name
from Rival__c
where name in :rivalNames];
Map rivalsMap = new Map();
for (Rival__c rival : rivals){
rivalsMap.put(rival.Name, rival);
}
return rivalsMap;
}
}
Hi David,
This is working good but i want to make clear that i have used 3 for loops will it be a problem. Is there any either way to overcome this help me out!!
trigger GetRival on Account (before insert, before update) {
set rivalValueSet = new set();
for (Account acc : Trigger.new)
{
if(acc.rival_Picklist__c != null)
rivalValueSet.add(acc.rival_Picklist__c)
}
for(Rival__c r : [select id, name from Rival__c where name IN: rivalValurSet])
rivalValueMap.add(r.name , r);
for(Account acc : Trigger.new)
{
if(acc.rival_Picklist__c != null && rivalValueMap.containskey(acc.rival_Picklist__c))
acc.rival__c = rivalValueMap.get(acc.rival_Picklist__c).id;
}
}
Thanks,
Saravanan
Sorry forgot to initialize rivalValueMap just a few changes in the code,
trigger GetRival on Account (before insert, before update) {
set rivalValueSet = new set();
map rivalValueMap = new map();
for (Account acc : Trigger.new)
{
if(acc.rival_Picklist__c != null)
rivalValueSet.add(acc.rival_Picklist__c)
}
for(Rival__c r : [select id, name from Rival__c where name IN: rivalValurSet])
rivalValueMap.add(r.name , r);
for(Account acc : Trigger.new)
{
if(acc.rival_Picklist__c != null && rivalValueMap.containskey(acc.rival_Picklist__c))
acc.rival__c = rivalValueMap.get(acc.rival_Picklist__c).id;
}
}
hello all, of all the knowledge i gained wil share wid all please go through (newbies like me)
Now firstly in the trigger above
SOql query is done inside for loop.
also trigger event should be before insert and before update.
trigger populateRivals on account(before insert,before update)
{
list rvl = [select id,Name__c from rival__c ];
map rvlMap = new map();
for(Rival__c r:rvl)
if(rvl!=null && rvl.size()>0)
{
{
rvlMap.put(r.Name__c,r.id);
}
}
for(account acc: trigger.new)
{
acc.Rival__c = rvlMap.get(acc.Rival_Picklist__c);
}
}
so,rvlMap.get(acc.Rival_Picklist__c); would check the map and return the id which it will populate it to
Rival___c (look up field to rival__c custom object)
if you declare data type of Rival__c as text field it will only display the id and not the name
NOTE :
trigger populateRivals on account(before insert,before update)
{
list rvl = [select id,Name__c from rival__c ];
map rvlMap = new map();
for(Rival__c r:rvl)
if(rvl!=null && rvl.size()>0)
{
{
rvlMap.put(r.Name__c,r.Name__c);
}
}
for(account acc: trigger.new)
{
acc.Rival__c = rvlMap.get(acc.Rival_Picklist__c);
}
}
here rival__c is just a text field and not a look up to custom object.
so, rvlMap.get(acc.Rival_Picklist__c); would return the name__c itself
if you declare rival__c as look up to rival__c object it will show error cz map returns the name but since its a look up relation it requires id and not name(which map returns).
I could understand the requirement
pls help what to populate on which object
elabotrate pls
not read all of the above, but here is my random stab, no idea if it compiles or not as I did it in sublime text without trying to save it back to my dev org:
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (after insert, after update) {
//Add trigger accounts into a list outside of the for loop for bulkification
List laccs = [SELECT Id, Name FROM Rival__c WHERE Name = trigger.new.Rival_Picklist__c]
for (Account acc : laccs) {
// Rival__c is a lookup to the Rival custom object
acc.Rival__c = laccs.id;
}
update acc;
}
Hi David,
Thank you for posting such a challenging thing (really learnt a lot of things from here).
Here are my observations:
1. There is a missing binding variable i.e.
Rival__c comp = [SELECT Id, Name FROM Rival__c WHERE Name = acc.Rival_Picklist__c];
It should be:
Rival__c comp = [SELECT Id, Name FROM Rival__c WHERE Name =: acc.Rival_Picklist__c];
2. The next catch is: It is an after update trigger, so we can’t update the fields of the objects related to Trigger.new.
So, here is the an alternate correct version of the trigger (had to introduce certain fields in my org as I could not run the same in your sfdc99 org):
trigger GetRivalDetails on Account (after Insert, after update) {
List rivalList = [select Name,ID from Rival__c];
Map mapRivalList = new MAP ();
for(Rival__c temp: rivalList)
{
mapRivalList.put(temp.Name,temp.ID);
}
Set accIds = new Set ();
for(Account acc: trigger.new)
{
accIds.add(acc.ID);
}
List accountsList = [SELECT Id, Rival__c, Rival_Picklist__c from Account where Id in :accIds];
List accountsForUpdate = new List();
for(Account acc1: accountsList )
{
if(mapRivalList.containsKey(acc1.Rival_Picklist__c))
{
if(acc1.Rival__c == null || acc1.Rival__c != mapRivalList.get(acc1.Rival_Picklist__c))
{
acc1.Rival__c = mapRivalList.get(acc1.Rival_Picklist__c);
accountsForUpdate.add(acc1);
}
}
}
update(accountsForUpdate);
}
Regards,
SK
hello
u have made the map for rival__C object
but later
mapRivalList.get(acc1.Rival_Picklist__c) for account
i dnt think thats possible
ignore the previous comment , i got bit confused
hello sk
in your code
acc1.Rival__c = mapRivalList.get(acc1.Rival_Picklist__c);
it would return the id and not the name i think.
No probs Chitral.. it happens..!
Sometimes, I also get confused on thinking as whether it would return id or value of the field :)
Regards,
S K
trigger PopulateRival on account (before insert,before update)
{
set PickValues=new set();
for(account t:trigger.new)
{
//get all picklist values in trigger.new, add them to a set
PickValues.add(t.PickRival__c);
}
//get rival records whose name is matched with piclklistvalues
list r_list=[select id,name from Rival__c where name in:PickValues];
//map the rival name to id
map r_map=new map();
for(Rival__c t2 : r_list)
{
r_map.put(t2.name,t2.id);
}
//get the rival id from map using picklistvalue, and assign to account lookup field
for(account t3 : trigger.new)
{
t3.Rival__c=r_map.get(t2.PickRival__c);
}
}
Check this Code..
// Automatically populate a lookup field to the Rival object
trigger GetRival on Account (before insert, before update) {
//Create a Map for storing the name And id;
Map RivalMap = new Map();
// List of all Rival Records
List RivalList = [SELECT id,Name From Rival__c];
for(Rival__c rv : RivalList){
// Put the Rival Name as a key of Map and Rival Id is a Value
RivalMap.put(RivalList,name, RivalList.id);
}
for (Account acc : Trigger.new) {
//Get the Rival Record Id from the Map based on the account’s Rival_Picklist__c field
acc.Rival__c = RivalMap.get(acc.Rival_Picklist__c).RivalList.id;
}
}
1. Never put SOQL inside a Loop!
2. Better to populate a Lookup Field using IDs instead of Name
3. Better to go with before insert, before update instead of after insert, after update since Account Ids are not needed.
Best Practice: I think that the way to go would be forcing the user to select the Rival Record from the Lookup Field. This would avoid coding, one less field :), APEX Usage (3M characters limit), speed optimized, duplicated picklist values that might generate errors.
However for education purpose, this is how I planned to fix the Trigger:
1. Get a List of all Rivals
2. Create and fill a Rivals Map
3. Iterate over each inserted/updated account to set the Rivals ID based on the previous Map
trigger GetRival on Account (before insert, before update){
//Get a List of all Rivals
List allRivals = [SELECT Id, Name FROM Rival__c];
//Crate a map with Rivals Names and their Ids
Map RivalsMap = new Map();
//Fill the map
for(List allRivals){
RivalsMaps.put(allRivals.Name, allRivals.Id);
}
//For each account
for(Account acc : Trigger.new){
acc.Rival__c = RivalsMaps.get(acc.Rival_Picklist__c);
}
}
PS. Is anyone around here going to Dreamforce??
trigger GetRival on Account (before insert, before update) { // trigger event should be before if DML needs to be performed
Set rivalPicklistValue = new Set();
for(Account a : trigger.new){
rivalPicklistValue.add(a.Rival_Picklist__c);
}
List comp = new List();
try{
comp = [SELECT Id, Name
FROM Rival__c
WHERE Name IN: rivalPicklistValue];
}catch(Exception e){
System.debug(‘Check List has no rows exception’+ e.getMessage());
}
Map rivalMap = new Map();
for(Rival__c r : comp){
rivalMap.put(r.Name,r);
}
for (Account acc : Trigger.new) {
// Rival__c is a lookup to the Rival custom object
if(rivalMap.containsKey(acc.Rival_Picklist__c)){
acc.Rival__c = rivalMap.get(acc.Rival_Picklist__c).id;
}
}
}
trigger GetRival on Account (before insert , before update) {
// Ceate picklist entries from schema.getDescribe()
List pkList = new List();
for(Schema.pickListEntry pe: Account.Rival_PickList__c.getDescribe().getPickListValues()){
pkList.add(pe.getValue());
}
//Create Map of Name,Id
Map rivalMap = new Map();
for(Rival__c rival : [SELECT id, name FROM Rival__c WHERE Name In :pkList]){
rivalMap.put(rival.Name, rival.Id);
}
// Check against newly inserted, updated Accounts
for(Account acc : Trigger.new){
if(rivalMap.containsKey(acc.Rival_PickList__c)){
acc.Rival__c = rivalMap.get(acc.Rival_PickList__c);
}
}
}
I wrote this freehand so if it is pasted into an org there may be a couple minor syntax issues. For bonus points I referenced a helper class with static flags to prevent trigger recursive firing.
I also added checks on update to update the lookup field if the picklist was changed to another value.
######################
HELPER CLASS BELOW
######################
public class SOME_HELPER_CLASS{
public static boolean UPDATE_FLAG = false;
public static boolean INSERT_FLAG = false;
}
#################
TRIGGER BELOW
#################
trigger GetRival on Account (before insert, before update) {
//Check trigger context and recursive fire flag for inserts
if(trigger.isInsert && SOME_HELPER_CLASS.INSERT_FLAG == false){
SOME_HELPER_CLASS.INSERT_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
if(tmp.Rival_Picklist__c != ”){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
//Check trigger context and recursive fire flag for updates
else if(trigger.isInsert && SOME_HELPER_CLASS.UPDATE_FLAG == false){
SOME_HELPER_CLASS.UPDATE_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
//Since this is happening in the update context, only store the value if it is new.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
//Check if this picklist was changed and if so then update the lookup field to reflect the change.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
}
}
Decided to log into a dev org and create the rival object and account fields. Just worked through the syntax errors so this trigger is complete(assuming the helper class is already in the org.)
trigger GetRival on Account (before insert, before update) {
//Check trigger context and recursive fire flag for inserts
if(trigger.isInsert && SOME_HELPER_CLASS.INSERT_FLAG == false){
SOME_HELPER_CLASS.INSERT_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
if(tmp.Rival_Picklist__c != ”){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
//Check trigger context and recursive fire flag for updates
else if(trigger.isInsert && SOME_HELPER_CLASS.UPDATE_FLAG == false){
SOME_HELPER_CLASS.UPDATE_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
//Since this is happening in the update context, only store the value if it is new.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
//Check if this picklist was changed and if so then update the lookup field to reflect the change.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
}
}
Okay I lied. Here is the final trigger lol. Man I wish I had the ability to delete my own comments on here :-)
trigger GetRival on Account (before insert, before update) {
//Check trigger context and recursive fire flag for inserts
if(trigger.isInsert && SOME_HELPER_CLASS.INSERT_FLAG == false){
SOME_HELPER_CLASS.INSERT_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
if(tmp.Rival_Picklist__c != ”){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
//Check trigger context and recursive fire flag for updates
else if(trigger.isupdate && SOME_HELPER_CLASS.UPDATE_FLAG == false){
SOME_HELPER_CLASS.UPDATE_FLAG = true;
list picklistValues = new list();
list rivalRecords = new list();
//Get rival picklist values from new accounts
for(account tmp : trigger.new){
//Since this is happening in the update context, only store the value if it is new.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
picklistValues.add(tmp.Rival_Picklist__c);
}
}
//If we found values then fetch appropriate rival records.
if(picklistValues.size() > 0){
rivalRecords = [select id, name from Rival__c where name IN: picklistValues ];
}
//If rival records were returned, then match each account to the rival record.
if(rivalRecords.size() > 0){
for(account tmp : trigger.new){
//Check if this picklist was changed and if so then update the lookup field to reflect the change.
if(tmp.Rival_Picklist__c != ” && tmp.Rival_Picklist__c != trigger.oldmap.get(tmp.id).Rival_Picklist__c){
for(Rival__c tmp2 : rivalRecords){
if(tmp.Rival_Picklist__c == tmp2.name){
tmp.Rival__c = tmp2.id;
break;
}
}
}
}
}
}
}
Yet to replicate this in my dev org but few issues that I can already see by looking at the trigger are:
1. Code not bulkified – No collection of Rival__c records to be updated is declared!
2. SOQL inside For loop = Invitation to governor limits violation!
3. DML statement to update the Rival__c records is missing
Might have more once I get a chance to replicate this in my Dev org :)
Now firstly in the trigger above
SOql query is done inside for loop.
also trigger event should be before insert and before update.
trigger populateRivals on account(before insert,before update)
{
list rvl = [select id,Name__c from rival__c ];
map rvlMap = new map();
for(Rival__c r:rvl)
if(rvl!=null && rvl.size()>0)
{
{
rvlMap.put(r.Name__c,r.id);
}
}
for(account acc: trigger.new)
{
acc.Rival__c = rvlMap.get(acc.Rival_Picklist__c);
}
}
so,rvlMap.get(acc.Rival_Picklist__c); would check the map and return the id which it will populate it to
Rival___c (look up field to rival__c custom object)
if you declare data type of Rival__c as text field it will only display the id and not the name
NOTE :
trigger populateRivals on account(before insert,before update)
{
list rvl = [select id,Name__c from rival__c ];
map rvlMap = new map();
for(Rival__c r:rvl)
if(rvl!=null && rvl.size()>0)
{
{
rvlMap.put(r.Name__c,r.Name__c);
}
}
for(account acc: trigger.new)
{
acc.Rival__c = rvlMap.get(acc.Rival_Picklist__c);
}
}
here rival__c is just a text field and not a look up to custom object.
so, rvlMap.get(acc.Rival_Picklist__c); would return the name__c itself
if you declare rival__c as look up to rival__c object it will show error cz map returns the name but since its a look up relation it requires id and not name(which map returns).