I'm Working through this challenge and appear to have run into an issue i have not found a solution to (nor does it appear that anyone has posted a question on this specifically.)
looking at the log is pretty painful as any System.debug() lines appear to be dropped due to the size of the log being >18MB but it appears there are 40000 rows to be added. Having caved and looked at some of the other code dumps out there i dont see that anyone else looks to have had this issue or made any special arrangements with batching and as far as i can see i haven't done anything drastically different to them (but the subtlety is clearly more than enough to cause an issue).
So if anyone could have a look over this and give me a hint as to where/why i have gone wrong it would be a great help. I'm not looking for a link to a working code set to copy i'm hoping for some understanding as to where my approach is incorrect/causing issues
With my trigger
trigger MaintenanceRequest on Case ( after update) {
List<Case> closedCases = new List<Case>();
for (Case c : Trigger.New){
System.debug('Type :' + c.Type );
System.debug('Equals Repair: ' +c.Type.equalsIgnoreCase('Repair'));
System.debug('Equals Routine Maintenance: ' +c.Type.equalsIgnoreCase('Routine Maintenance'));
if (
(c.Type.equalsIgnoreCase('Repair') || c.Type.equalsIgnoreCase('Routine Maintenance'))
&& c.isClosed == true )
{
closedCases.add(c);
}
}
System.debug(closedCases.size() + ' cases were closed');
if(closedCases.size() > 0){
MaintenanceRequestHelper.createScheduledMaintainance(closedCases);
}
}
and helper
public with sharing class MaintenanceRequestHelper {
public MaintenanceRequestHelper() {
}
public static Map<Id,Integer> getMainainanceCycleForCases(){
List<AggregateResult> maintainTimes = [SELECT Maintenance_Request__c, MIN(Equipment__r.Maintenance_Cycle__c)cycle
FROM Equipment_Maintenance_Item__c
GROUP BY Maintenance_Request__c
];
System.debug(maintainTimes);
Map<Id,Integer> maintinTimeMap = new Map<Id,Integer>();
for( AggregateResult e : maintainTimes ){
maintinTimeMap.put((Id)e.get('Maintenance_Request__c'), ((Double)e.get('cycle')).intValue());
}
System.debug(maintinTimeMap);
return maintinTimeMap;
}
public static Map<Id,List<Id>> getMaintainanceItems(List<Case> closedCases){
// map maintainance_Request_ID, Equipment_Maintenance_Item__c
List<Equipment_Maintenance_Item__c> equipmentMaintainanceList = [SELECT Maintenance_Request__c,
Equipment__r.Id
FROM Equipment_Maintenance_Item__c
Where Maintenance_Request__c IN :closedCases];
Map<Id,List<Id>> maintainance_equipmentMap = new Map<Id, List<Id>>();
for (Equipment_Maintenance_Item__c e:equipmentMaintainanceList){
System.debug('Putting : '+ e.Maintenance_Request__c + ' : ' + e.Equipment__r.Id);
if(maintainance_equipmentMap.containsKey(e.Maintenance_Request__c)){
maintainance_equipmentMap.get(e.Maintenance_Request__c).add(e.Equipment__r.Id);
}else{
maintainance_equipmentMap.put(e.Maintenance_Request__c,new List<id>{e.Equipment__r.Id});
}
System.debug('Map now : '+ maintainance_equipmentMap);
}
System.debug('Returning: ' +maintainance_equipmentMap);
return maintainance_equipmentMap;
}
public static void createScheduledMaintainance(List<Case> closedCaseList) {
System.debug(closedCaseList.size() + ' Cases to create');
Map<Id,Integer> maintainTimeMap = getMainainanceCycleForCases();
Map<Id,List<Id>> maintainanceItems = getMaintainanceItems(closedCaseList); // map maintainance_Request_ID, Equipment_Maintenance_Item__c
List<Case> createNewCases = new List<Case>();
for(Case c : closedCaseList){
Case newCase = new Case();
newCase.Type = 'Routine Maintenance';
newCase.Status = 'New';
newCase.Vehicle__c = c.Vehicle__c;
newCase.Subject = c.Subject;
newCase.Date_Reported__c = Date.today();
newCase.Date_Due__c = Date.today() + maintainTimeMap.get(c.Id);
newCase.ProductId = c.ProductId;
createNewCases.add(newCase);
}
System.debug(createNewCases.size() +' to insert');
list<Equipment_Maintenance_Item__c> itemsListToinsert= new list<Equipment_Maintenance_Item__c>();
if(createNewCases.size()>0){
insert createNewCases;
for(Case ca : createNewCases){
for(Id key: maintainanceItems.keySet()){
List<Id> equipment = maintainanceItems.get(key);
for (Id e : equipment){
Equipment_Maintenance_Item__c newitem = new Equipment_Maintenance_Item__c();
newitem.Equipment__c=e;
newitem.Maintenance_Request__c= ca.Id;
itemsListToinsert.add(newitem);
}
}
}
}
System.debug('itemsListToinsert Size: ' +itemsListToinsert.size());
if (itemsListToinsert.size() >0){
insert itemsListToinsert; //<<<< ERROR TRIGGERS HERE and has ~40000 rows <<<<<
}
}
}
So, It seems i was over complicating the issue to an extent.
Having taken a break and walking through the problem again something just didnt sit right with this block of code.
if(createNewCases.size()>0){
insert createNewCases;
for(Case ca : createNewCases){
for(Id key: maintainanceItems.keySet()){
List<Id> equipment = maintainanceItems.get(key);
for (Id e : equipment){
Equipment_Maintenance_Item__c newitem = new Equipment_Maintenance_Item__c();
newitem.Equipment__c=e;
newitem.Maintenance_Request__c= ca.Id;
itemsListToinsert.add(newitem);
}
}
}
}
For -> For -> For -> create new Equipment_Maintenance_Item__c
With 0 checks to see if this new Equipment_Maintenance_Item__c was needed.
I ended up partly re-writing the class but the main change was re-working the section of code above to
List<Equipment_Maintenance_Item__c> equipmentMaintainanceList = [SELECT Maintenance_Request__c,
Equipment__r.Id
FROM Equipment_Maintenance_Item__c
Where Maintenance_Request__c IN :closedCaseList];
List<Equipment_Maintenance_Item__c> updatedEquipment = new List<Equipment_Maintenance_Item__c>();
for(Case closed : closedCaseList){
for(Equipment_Maintenance_Item__c eqip : equipmentMaintainanceList){
if (eqip.Maintenance_Request__c == closed.Id){
Equipment_Maintenance_Item__c e = eqip.clone(false, false, false, false);
e.Maintenance_Request__c = oldToNewMap.get(closed.Id).Id;
updatedEquipment.add(e);
}
}
}
if (updatedEquipment.size() > 0 ){
insert updatedEquipment;
}
For me the lesson is be very mindful of nested for loops when the outcome is going to come up against some hard and fast governor limits.
Related
The purpose here is to Remove Product Sharing When user is removed from AccountTeamMember.
List<AccountTeamMember> acctmListProd = [Select id,UserId, AccountId, TeamMemberRole FROM
AccountTeamMember WHERE Id In:acctmList and
TeamMemberRole IN:Roles]
Map<Id,Id> accToUserIdList = new Map<Id,Id>();
for(AccountTeamMember At: acctmListProd)
{
accToUserIdList.put(At.AccountId, At.UserId);
}
List<Product__Share> DelProdShareRecords = new List<Product__Share>();
Set<Id> productIds = new Set<Id>();
for(Id accId: accToUserIdList.keySet())
{
List<Product__c> prodList = [Select id,Account__c from Product__c where
Account__c=accId];
for(Product__c prod: prodList)
{
productIds.add(prod.Id);
}
List<Product__Share> prodShareRecords = [Select id,ParentId,UserOrGroupId from
Product__Share where ParentId IN:productIds AND
UserOrGroupId=accToUserList.get(accId)
];
DelProdShareRecords.addAll(prodShareRecords);
}
if(!DelProdShareRecords.isEmpty())
{
Database.deleteResult[] result = Database.delete(DelProdShareRecords, false);
}
https://ideas.salesforce.com/s/idea/a0B8W00000GdgUVUAZ/allow-global-security-and-sharing-rules-settings-on-products
Product__Share isn't a thing. This code looks like it was never compiled or tested in an org.
I have a challenge to complete. The requirement is automate record creation of a new Case record(renamed maintenance request). When an existing maintenance request(Case record) of type Repair or Routine Maintenance is closed, create a new maintenance request(Case record) for a future routine checkup. This new maintenance request is tied to the same Vehicle and Equipment(Product2- Standard Object renamed) Records as the original closed request. There is a logic on the due date field. It should have the min date compared to all the maintenance cycle of the equipment record related to the maintenance request.
I separated the logic in a helper class for the trigger. I believe the helper class code logic for 'Equipment Maintenance Item' record creation is not the right approach but trailhead already accepted it and provided me 500 points. Please help me find the right approach for the new 'Equipment Maintenance Item' record creation logic.
(The 'Equipment Maintenance Item' object is a Junction Object)
image
2 standard objects are used:
Maintenance Request (renamed Case) and Equipment (renamed Product)
2 custom objects are used:
Vehicle and Equipment Maintenance Item
Trigger:
trigger MaintenanceRequest on Case (before update, after update) {
if(Trigger.isAfter){
MaintenanceRequestHelper.updateWorkOrders(Trigger.New);
}}
Helper Class:
public with sharing class MaintenanceRequestHelper {
public static void updateWorkOrders(List<Case> CaseList) {
integer i=0;
List<Case> NewCaseList = new List<Case>();
List<Equipment_Maintenance_Item__c> eList = [SELECT Id,Maintenance_Request__c,Equipment__c,Quantity__c
FROM Equipment_Maintenance_Item__c
WHERE Maintenance_Request__c IN: CaseList];
List<Aggregateresult> mindue = new List<Aggregateresult>([SELECT MIN(Equipment__r.Maintenance_Cycle__c)MinimumValue
FROM Equipment_Maintenance_Item__c WHERE Maintenance_Request__c IN: CaseList]);
integer k=0;
List<Equipment_Maintenance_Item__c> newEmi = new List<Equipment_Maintenance_Item__c>();
for(Case c : CaseList){
if(c.Status == 'Closed' && (c.type =='Repair' || c.type =='Routine Maintenance')){
Case c1 = new Case(
Status = 'New',
Vehicle__c = c.Vehicle__c,
Type = 'Routine Maintenance',
Subject = 'Routine Checkup',
Date_Reported__c = Date.today(),
Product__c = c.Product__c,
AccountId = c.AccountId,
ContactId = c.ContactId,
Origin = c.Origin
//Date_Due__c = Date.today()
);
NewCaseList.add(c1);
for(Equipment_Maintenance_Item__c emi : eList){
if(c.Id == emi.Maintenance_Request__c){
newEmi.add(new Equipment_Maintenance_Item__c(
Equipment__c = emi.Equipment__c,
Maintenance_Request__c = c.Id,
Quantity__c = emi.Quantity__c));
}
}
for(Aggregateresult r:mindue){
if(r.get('MinimumValue')!=NULL){
NewCaseList[i].Date_Due__c=system.today()+integer.valueof(r.get('MinimumValue'));
}
i++;
}
}
}
if(NewCaseList.size()>0){
insert NewCaseList;
}
for(Case c2: NewCaseList){
for(Equipment_Maintenance_Item__c emi2 : newEmi){
emi2.Maintenance_Request__c = c2.id;
}
}
insert newEmi;
}
}
Your Code is correct but not bulkified. It will work for a single record and it will fail in case a bunch of records closed at the same time. I have solved it by creating one field on the Case object which will store cloned Case Id i.e. the old case from which the new case has been created.
Please refer code sample below:
trigger MaintenanceRequest on Case (before update, after update) {
//ToDo: Call MaintenanceRequestHelper.updateWorkOrders
if(trigger.isAfter){
MaintenanceRequestHelper.updateWorkOrders(trigger.new);
}
}
public with sharing class MaintenanceRequestHelper {
public static void updateWorkOrders(List<Case> newList) {
// TODO: Complete the method to update workorders
List<Case> CreateMaintReqLst = new List<Case>();
Set<Id> caseIdsSet = new Set<Id>();
List<Equipment_Maintenance_Item__c> newEMI = new List<Equipment_Maintenance_Item__c>();
for (Case caseRec : newList)
{
if(caseRec.Status == 'Closed' &&
(caseRec.Type =='Repair' || caseRec.Type =='Routine Maintenance'))
{
caseIdsSet.add(caseRec.Id);
}
}
List<Case> CaseList = [SELECT Id,Type,Status,Vehicle__c,Subject,Date_Reported__c,Date_Due__c,ProductId,Product__c,
(select Id,Maintenance_Cycle__c,Equipment__c,Quantity__c FROM Equipment_Maintenance_Items__r)
FROM Case
WHERE Id in:caseIdsSet];
for(Case caseRec:CaseList){
Integer minMaintCycle = 0;
List<Equipment_Maintenance_Item__c> EqpMaintList = caseRec.Equipment_Maintenance_Items__r;
if(EqpMaintList.size()>0){
for(Equipment_Maintenance_Item__c EquipMaint:EqpMaintList){
newEMI.add(new Equipment_Maintenance_Item__c(
Equipment__c = EquipMaint.Equipment__c,
Maintenance_Request__c = caseRec.Id,
Quantity__c = EquipMaint.Quantity__c));
if(Integer.valueOf(EquipMaint.Maintenance_Cycle__c) < minMaintCycle || minMaintCycle == 0){
minMaintCycle =Integer.valueOf(EquipMaint.Maintenance_Cycle__c);
}
}
}
Case newCase = new Case();
newCase.Type = 'Routine Maintenance';
newCase.Status = 'New';
newCase.Vehicle__c = caseRec.Vehicle__c;
newCase.Subject = String.isBlank(caseRec.Subject) ? 'Routine Maintenance Request' : caseRec.Subject;
newCase.Date_Reported__c = Date.today();
newCase.Date_Due__c = Date.today().addDays(minMaintCycle);
newCase.ProductId = caseRec.ProductId;
newCase.Product__c = caseRec.Product__c;
newCase.Cloned_Closed_Case_Id__c = caseRec.Id;
CreateMaintReqLst.add(newCase);
}
if(CreateMaintReqLst.size()>0){
Database.insert(CreateMaintReqLst);
}
for(Case c2: CreateMaintReqLst){
for(Equipment_Maintenance_Item__c emi2 : newEmi){
if(c2.Cloned_Closed_Case_Id__c == emi2.Maintenance_Request__c){
emi2.Maintenance_Request__c = c2.id;
}
}
}
if(newEmi.size()>0){
Database.insert(newEmi);
}
}
}
I am trying to deploy a trigger to prod on salesforce. I was hoping someone could help me with an example of tests for this trigger.
Here is my trigger. It does its purpose, which is to update a bool field when a new contentNote (or anything of content type) that then has collateral effects through process builder.
trigger NewNote on ContentDocumentLink (before insert) {
Set<Id> setParentId = new Set<Id>();
List<Client_Relationships__c> crlst = new List<Client_Relationships__c>();
for (ContentDocumentLink cdl : trigger.new ) {
setParentId.add(cdl.LinkedEntityId);
}
crlst = [select Id , newNote__c from Client_Relationships__c where Id IN :setParentId];
For(Client_Relationships__c e : crlst)
{
e.newNote__c = True;
}
update crlst;
}
The trigger you wrote can be more efficient by omitting the SOQL query as seen below:
trigger NewNote on ContentDocumentLink (before insert) {
List<Client_Relationships__c> crlst = new List<Client_Relationships__c>();
for (ContentDocumentLink cdl : trigger.new ) {
if(cdl.LinkedEntityId.getSObjectType().getDescribe().getName() == 'Client_Relationships__c'){
crlst.add(
new Client_Relationships__c(
Id = cdl.LinkedEntityId,
newNote__c = true
)
);
}
}
update crlst;
}
The best practice would be to add your code to a handler or utility class and to only have one trigger per object. The name of this trigger could be changed to "ContentDocumentLinkTrigger" if you adopt that practice.
The test class for that trigger is below. I could not test the compilation because I don't have the same custom object.
#IsTest
private class ContentDocumentLinkTriggerTest {
#TestSetup
static void setupTest() {
insert new ContentVersion(
Title = 'Test_Document.txt',
VersionData = Blob.valueOf('This is my file body.'),
SharingPrivacy = 'N',
SharingOption = 'A',
Origin = 'H',
PathOnClient = '/Test_Document.txt'
);
List<Client_Relationships__c> relationships = new List<Client_Relationships__c>();
for(Integer i = 0; i < 300; i++){
relationships.add(
new Client_Relationships__c(
//add required field names and values
)
);
}
insert relationships;
}
static testMethod void testInsertTrigger() {
//prepare data
List<ContentVersion> contentVersions = new List<ContentVersion>([
SELECT Id, ContentDocumentId FROM ContentVersion
]);
System.assertNotEquals(0, contentVersions.size(), 'ContentVersion records should have been retrieved');
List<Client_Relationships__c> relationships = getAllClientRelationships();
System.assertNotEquals(0, relationships.size(), 'Client Relationship records should have been retrieved.');
List<ContentDocumentLink> documentLinks = new List<ContentDocumentLink>();
for(Integer i = 0; i < 252; i++){
documentLinks.add(
new ContentDocumentLink(
ContentDocumentId = contentVersions[0].ContentDocumentId,
LinkedEntityId = relationships[i].Id,
ShareType = 'I'
)
);
}
//test functionality
Test.startTest();
insert documentLinks;
Test.stopTest();
//assert expected results
List<Client_Relationships__c> relationshipsAfterProcessing = getAllClientRelationships();
for(Client_Relationships__c relationship : relationshipsAfterProcessing){
System.assert(relationship.newNote__c, 'The newNote__c field value should be true.');
}
}
private static List<Client_Relationships__c> getAllClientRelationships(){
return new List<Client_Relationships__c>([
SELECT Id, newNote__c FROM Client_Relationship__c
]);
}
}
For setting up test data, it is helpful to have a utility class that centralizes the creation of well-formed records. This is extremely useful when your code base gets large and a validation rule affects the insertion of new data in many test classes. With a centralized method, the inserted data only needs to be altered once.
I am new to salesforce and I am stuck with a situation here.
I have a class which is scheduled every hour. I hit an account with the below code and an email is sent out to MAROPOST (Marketing automation tool). When this happen I want to track the Account and create a case or a log which says Welcome Email is sent so that I don't hit the same Account again.
Please help. Below is the working class. Please help
public class PD_WelcomeMaroPost {
public static string sendEmailThroughMaro(string myInpEmail) {
string successContacts = '';
string failureContacts = '';
// SQL to fetch FBO who Joined Today
list<Account> conts = new list<Account> ([SELECT name, Email_FLP_com__c,
(SELECT Id
FROM Stripe_Subscriptons__r
WHERE Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false
LIMIT 1)
from account
where ID IN (
select Distributor__c
from Stripe_Subscripton__c
where Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false)
AND Email_FLP_com__c != NULL
LIMIT 100]);
system.debug('>>>>>>>>>>' + conts);
overallEmail myEmail = new overallEmail();
List<Stripe_Subscripton__c> subsToUpdate = new List<Stripe_Subscripton__c>();
for(Account c : conts){
myEmail.email.campaign_id = 172;
myEmail.email.contact.Email = c.Email_FLP_com__c;
myEmail.email.contact.first_name = c.name;
/**MAp<String, String> tags = new Map<String, String>();
tags.put('firstName', c.name);
myEmail.email.tags = tags;**/
system.debug('#### Input JSON: ' + JSON.serialize(myEmail));
try{
String endpoint = 'http://api.maropost.com/accounts/1173/emails/deliver.json?auth_token=j-V4sx8ueUT7eKM8us_Cz5JqXBzoRrNS3p1lEZyPUPGcwWNoVNZpKQ';
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('POST');
req.setHeader('Content-type', 'application/json');
req.setbody(JSON.serialize(myEmail));
Http http = new Http();
system.debug('Sending email');
HTTPResponse response = http.send(req);
system.debug('sent email');
string resultBodyGet = '';
resultBodyGet = response.getBody();
system.debug('Output response:' + resultBodyGet);
maroResponse myMaroResponse = new maroResponse();
myMaroResponse = (maroResponse) JSON.deserialize(resultBodyGet, maroResponse.class);
system.debug('#### myMaroResponse: ' + myMaroResponse);
if(myMaroResponse.message == 'Email was sent successfully')
successContacts = successContacts + ';' + c.Email_FLP_com__c;
else
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
}
catch (exception e) {
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
system.debug('#### Exception caught: ' + e.getMessage());
}
c.Stripe_Subscriptons__r[0].Welcome_Email__c = true;
subsToUpdate.add(c.Stripe_Subscriptons__r[0]);
}
Update subsToUpdate;
return 'successContacts=' + successContacts + '---' + 'failureContacts=' + failureContacts;
}
public class maroResponse {
public string message {get;set;}
}
public class overallEmail {
public emailJson email = new emailJson();
}
public class emailJson {
public Integer campaign_id;
public contactJson contact = new contactJson();
// Public Map<String, String> tags;
}
public class contactJson {
public string email;
public string first_name;
}
}
You're making a callout in a loop, there's governor limit of max 100 callouts. See Limits class to obtain current & max numbers programatically rather than hardcoding it.
Other than that it should be pretty simple change. First add your filter to the query and add a "subquery" (something like a JOIN) that pulls the related list of subscriptions
list<Account> conts = new list<Account> ([SELECT name, Email_FLP_com__c,
(SELECT Id
FROM Stripe_Subscriptions__r
WHERE Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false
LIMIT 1)
from account
where ID IN (
select Distributor__c
from Stripe_Subscripton__c
where Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false)
AND Email_FLP_com__c != NULL
LIMIT 100]);
Then it's just few lines more
List<Stripe_Subscription__c> subsToUpdate = new List<Stripe_Subscription__c>();
for(Account a : conts){
// do your maropost code here
a.Stripe_Subscriptions__r[0].Welcome_Email__c = true;
subsToUpdate.add(a.Stripe_Subscriptions__r[0]);
}
update subsToUpdate;
Of course you might want to set that checkbox to true only if callout went OK ;)
After reading your code, I don't see where you tried to accomplish this. If you post your attempt I'd be glad to help fix it.
Instead I'll give you different logic for what you are trying to do.
1.) create new checkbox field
2.) in batch query where box is not checked
3.) send email
4.) check checkbox
to answer your comment here is some sample code, you will need to fix it yourself, i am just making temp names
for(sobjectname gg:[your query]){
Send email;
gg.checkbox = checked;
update gg;
}
it'd be better to make it bulkified though
list<yourSObject> tobeupdated = new list<yourSObject>([Your query]);
for(yourSObject gg: tobeupdated){
send email;
gg.checkbox = true;
}
update tobeupdated;
I am doing a fairly simple query for contact records using dynamic soql using the following method:
public PageReference contactSearch() {
contactResultSetSize = 0;
if(!String.isEmpty(firstname) || !String.isEmpty(lastname) || !String.isEmpty(company)) {
string soql = 'Select firstname, lastname, account.Name, account.BillingStreet, account.BillingCity, account.BillingState, account.BillingPostalCode From Contact';
String whereClause = '';
if(!String.isEmpty(firstname)) {
whereClause = ' Where firstname like \'%' + firstname + '%\'';
}
if(!String.isEmpty(lastname)) {
if(!String.isEmpty(firstname)) {
whereClause += ' AND lastname like \'%' + lastname + '%\'';
}
else {
whereClause = ' Where lastname like \'%' + lastname + '%\'';
}
}
if(!String.isEmpty(company)) {
if(!String.isEmpty(firstname) || !String.isEmpty(lastname)) {
whereClause += ' AND account.Name like \'%' + company + '%\'';
}
else {
whereClause = ' Where account.Name like \'%' + company + '%\'';
}
}
soql = soql + whereClause;
List<Contact> searchResults = Database.query(soql);
contactResultSetSize = searchResults.size();
if(contactLinesForPage == null) {
contactLinesForPage = new List<ContactWrapper>();
}
for(Contact c : searchResults) {
contactLinesForPage.add(new ContactWrapper(contactLinesForPage.size(), c, ''));
}
}
return null;
}
I am using a wrapper class and contactLinesForPage is a list of my wrapper object:
public List<ContactWrapper> contactLinesForPage {get; set;}
As a user does multiple searches, I don't want to re-add records to the searchResults list. How can I check if a record already exists in my object so I don't have duplicate records returned in the search?
Thanks for any help.
Or you could use a map. Add the ContactWrapper objects to the map. The key to the map is an id. If they add a duplicate contact it will simply overwrite the one already there. Your code would simply be
aMap.put(cw.id, cw); // one line eliminates duplicates.
When you want the list of ContactWrappers, simply return aMap.values();
If you want to abstract the behavior of maintaining the collection of Contacts, create a ContactCollection class and hide the implementation in there. This would provide something more reusable as well as a good pattern for similar situations.
Just add a check if contactLinesForPage allready contains this contact. Something like this:
for(Contact c : searchResults) {
Boolean toInsert = true;
for(ContactWrapper cw : contactLinesForPage){
if(cw.contact.Id == c.Id){
toInsert=false;
}
}
if(toInsert){
contactLinesForPage.add(new ContactWrapper(contactLinesForPage.size(), c, ''));
}
}