+ Start a Discussion
anup-prakashanup-prakash 

scenario For usage of Maps and sets

Hi I have been working on salesforce for quite a while now. Despite that I consider myself as a beginner.. Can you Please give me scenarios as to where I will have to use sets and Maps.. I have used Lists and I am comfortable with It but I have never faced a scenario as to when I have to use a Map and Set in differnt scenerio.. so that I could help me to understand the usage of these two collection elements..

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
Kiran  KurellaKiran Kurella

Hey Anup,

 

I took Avidev9 code and optimized it further to use sets and maps appropriately. You can use a set or map, if you want to capture unique values. In this trigger / example, I elimated the several lines of iteration code by using sets and maps effectively.

 

If this post solves your problem kindly mark it as solution. if this post is helpful please throw Kudos.

 

trigger CheckDuplicateAttachment on Attachment(before insert, before update) {
    set<Id> attachIds = new set<Id>();
    Map <Id, Set <String>> attMap = new Map <Id, Set <String>> ();

	// gather various attachment ids
    for (Attachment a: Trigger.new) {
		if (trigger.isInsert || a.Name != trigger.oldMap.get(a.Id).Name) attachIds.add(a.ParentId);
    }

	// query the database only when there is a change in the Attachment Name or a new Attachment is added.
    if (!attachIds.isEmpty()) {
	for (Attachment a: [Select parentId, Name from Attachment where parentId = : attachIds]) {
		if (!attMap.containsKey(a.ParentId)) attMap.put(a.ParentId, new Set <String>{});
		attMap.get(a.ParentId).add(a.Name);
	}

   	for (Attachment a: Trigger.new) {
   		// if the existing attachment map contains the name then throw an error 
		if ((trigger.isInsert || a.Name != trigger.oldMap.get(a.Id).Name) && attMap.containsKey(A.ParentId) && attMap.get(A.ParentId).contains(a.Name)) {
			A.addError('Attachment by this Name already exists in this fiscal Year');
        }
	}
   }
}

 

All Answers

Avidev9Avidev9
Have a look at this post that I just answered http://boards.developerforce.com/t5/Apex-Code-Development/URGENT-caused-by-System-LimitException-Too-many-SOQL-queries-101/td-p/628489

This will give you slight Idea why and when to use collections.
here we minimized the SOQL calls by taking the SOQL out of the loop.
anup-prakashanup-prakash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
trigger CheckDuplicate on Fiscal_Year__c (before insert, before update) {

for(fiscal_year__c fy: Trigger.new){
String fiscalYearName = fy.name;
String divisionName = fy.Division__c;
List<String> fiscalYearNameList = new list<String>();

for(fiscal_year__c fy1 : [select Name from fiscal_year__c where division__r.ID =: divisionName]){

fiscalYearNameList.add(fy1.Name);
}

for(String s : fiscalYearNameList){
if(fiscalYearName.equals(s)){
fy.Name.addError('Same Fiscal Year value already Present for this Division');
}
}
}
}


So is this wrong practice or is it okay?
anup-prakashanup-prakash
And how about this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
trigger CheckDuplicateAttachment on Attachment (before insert, before update) {

/* String fiscalYearID;
String divisionID; */
String attachName;
String attachParentID;
List<String> attachListNames = new List<String>();

for(Attachment A : Trigger.new){
attachParentID = A.ParentId;
attachName = A.Name;

for(Attachment Att: [Select Name from Attachment where parentID =: attachParentID ]){
attachListNames.add(Att.Name);
}

for(String s : attachListNames ){
if(attachName.equals(s)){
A.addError('Attachment by this Name already exists in this fiscal Year');
}
}
}
}
Avidev9Avidev9
Both of them are not good!
You have SOQL inside nested for Loop.
So if there are are say 200 records the inner loop will be called 200 times and hence 200 SOQL and you will get an exception
anup-prakashanup-prakash
Avi thanks for letting me know that. so how can I correct this trigger
Avidev9Avidev9
Have a look at the code I shared earlier, you will get an Idea how to bulkify a trigger.
The link contains both bad and fixed/bulkified trigger
anup-prakashanup-prakash
trigger CheckDuplicateAttachment on Attachment (before insert, before update) {

String attachName;
String attachParentID;
List<String> attachListNames = new List<String>();

for(Attachment A : Trigger.new){
attachParentID = A.ParentId;
attachName = A.Name;
}

for(Attachment Att: [Select Name from Attachment where parentID =: attachParentID ]){
attachListNames.add(Att.Name);
}

for(Attachment A : Trigger.new){
for(String s : attachListNames ){
if(attachName.equals(s)){
A.addError('Attachment by this Name already exists in this fiscal Year');
}
}
}
}

Is this code Okay now? If you could tell without being troubled..
Avidev9Avidev9
trigger CheckDuplicateAttachment on Attachment(before insert, before update) {

    String attachName;
    String attachParentID;
    List < Id > attachIds = new List < Id > ();
    Map < Id, Set < String >> attMap = new Map < Id, Set < String >> ();
    for (Attachment A: Trigger.new) {
        attachIds.add(A.ParentId);
    }

    for (Attachment A: [Select Name from Attachment where parentID = : attachIds]) {
        if (attMap.get(A.ParentId) == NULL) {
            attMap.put(A.ParentId, new Set < String > {
                    A.Name
                });
        }

        attMap.get(A.ParentId).add(A.Name);
    }

    for (Attachment A: Trigger.new) {
        Set < String > attNames = attMap.get(A.ParentId);
        if (attNames != NULL)
            for (String s: attNames) {
                if (attachName.equals(s)) {
                    A.addError('Attachment by this Name already exists in this fiscal Year');
                }
        }
    }
}

I just wrote this for you in a notepad may not work. But contains all the logic you need it to work

 

 PS : Am not troubled, I want you to understand the basics here

Kiran  KurellaKiran Kurella

Hey Anup,

 

I took Avidev9 code and optimized it further to use sets and maps appropriately. You can use a set or map, if you want to capture unique values. In this trigger / example, I elimated the several lines of iteration code by using sets and maps effectively.

 

If this post solves your problem kindly mark it as solution. if this post is helpful please throw Kudos.

 

trigger CheckDuplicateAttachment on Attachment(before insert, before update) {
    set<Id> attachIds = new set<Id>();
    Map <Id, Set <String>> attMap = new Map <Id, Set <String>> ();

	// gather various attachment ids
    for (Attachment a: Trigger.new) {
		if (trigger.isInsert || a.Name != trigger.oldMap.get(a.Id).Name) attachIds.add(a.ParentId);
    }

	// query the database only when there is a change in the Attachment Name or a new Attachment is added.
    if (!attachIds.isEmpty()) {
	for (Attachment a: [Select parentId, Name from Attachment where parentId = : attachIds]) {
		if (!attMap.containsKey(a.ParentId)) attMap.put(a.ParentId, new Set <String>{});
		attMap.get(a.ParentId).add(a.Name);
	}

   	for (Attachment a: Trigger.new) {
   		// if the existing attachment map contains the name then throw an error 
		if ((trigger.isInsert || a.Name != trigger.oldMap.get(a.Id).Name) && attMap.containsKey(A.ParentId) && attMap.get(A.ParentId).contains(a.Name)) {
			A.addError('Attachment by this Name already exists in this fiscal Year');
        }
	}
   }
}

 

This was selected as the best answer
anup-prakashanup-prakash
Thanks Avi. And Thanks CodeWizard.. The help you have provided was Immense and couldn't have asked for more... God Bless.!!