0

Note* I am a beginner attempting to jump from level 1 to level 10 coding because there is no easy way to accomplish the task.

I need to prevent users from inserting duplicates of a custom object based on two related object lookup fields. The best way to accomplish this is to wrap them into a class so apex is not mixing up the values during batches. I have successfully created a wrapper class but I cannot seem to pass and evaluate the list properly. I am getting the following errors:

  1. Error:Constructor not defined: [ChangeOrderTriggerHandler.ChangeOrderWrapper].()
    • From my understanding, I do not have a constructor set up for this type but I cannot find documentation to help guide me into creating this?
  2. Error:Comparison arguments must be compatible types: Id, Object
    • I don't quite understand this as the comparisons are both using id.field

If this is all incorrect I wouldn't be surprised, just let me know. Thanks in advance!

public with sharing class ChangeOrderTriggerHandler {
    public class ChangeOrderWrapper{
        public Asset ast {
            get ; private set;
        }
        public Opportunity opp {
            get ; private set;
        }

        public ChangeOrderWrapper(Asset a, Opportunity o) {
            this.ast = a;
            this.opp = o;
        }
    }

    public List<ChangeOrderWrapper> wrapperList {
        get ; private set;
    }

    public ChangeOrderTriggerHandler() {
        Map<Id, Asset> astMap = new Map<Id, Asset>
            ([SELECT Id FROM Asset WHERE Id IN (SELECT Asset__c FROM Change_Order__c WHERE Status__c = 'Open' )]);
        Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>
            ([SELECT Id FROM Opportunity WHERE Id IN (SELECT Opportunity__c FROM Change_Order__c WHERE Status__c = 'Open' )]);
        List<Change_Order__c> cOrders = [SELECT Asset__c, Opportunity__c FROM Change_Order__c WHERE Status__c = 'Open'];

        this.wrapperList = new List<ChangeOrderWrapper>();

        for(Change_Order__c co : cOrders)
        {
            this.wrapperList.add(new ChangeOrderWrapper(astMap.get(co.Asset__c),oppMap.get(co.Opportunity__c)));
        }
        system.debug('wrapperListSize-->'+this.wrapperList.size());
        system.debug('wrapperList-->'+this.wrapperList);

    }
    public static void ChangeOrderDuplicateChecker(List<Change_Order__c> cos)
    {   ChangeOrderWrapper cow = new ChangeOrderWrapper();

            for(Change_Order__c co : trigger.new)
            {
                if(co.asset__c == cow.ast && co.opportunity__c == cow.opp)
                {
                    co.addError('Testing');
                }
            }
    }

}

1 Answer 1

0

Regarding your errors,

For error 1: You are calling the constructor without any parameter, but you defined your constructor to accept two parameters.

For error 2: co.asset__c is a lookup field (of Id data type), but you are comparing it against an SObject.

public static void ChangeOrderDuplicateChecker(List<Change_Order__c> cos)
{   ChangeOrderWrapper cow = new ChangeOrderWrapper();

        for(Change_Order__c co : trigger.new)
        {
            if(co.asset__c == cow.ast && co.opportunity__c == cow.opp)
            {
                co.addError('Testing');
            }
        }
}

To your question, I think you are complicating things a little bit. You can build a composite keys based on asset and opportunity lookup field and check if it already presents:

Set<Id> assetIds = new Set<Id>();
Set<Id> oppIds = new Set<Id>();
for(Change_Order__c co : trigger.new) {
    assetIds.add(co.asset__c);
    oppIds.add(co.opportunity__c);
}
Set<String> compositeKeys = new Set<String>();
for (Change_Order__c co : [SELECT asset__c, opportunity__c FROM Change_Order__c WHERE asset__c = :assetIds OR opportunit__c = :oppIds]) {
    compositeKeys.add(co.asset__c + co.opportunity__c);
}

for(Change_Order__c co : trigger.new) {
    if (compositeKeys.contains(co.asset__c + co.opportunity__c)) {
        co.addError('Duplicate found!');
    }
}

Or, you might be able to use no-code solution: Duplicate Rules

8
  • I don't think duplicate rules will work. IIRC duplicate rules will only let you set one of the fields to a lookup. We built out custom dup logic much like what you have above because of this.
    – gNerb
    Jun 10, 2020 at 14:48
  • I am getting an error: Arithmetic expressions must use numeric arguments. Am I supposed to add hashcode to this? Also, duplicate rules will not work with two lookup fields, this is why I am having a hard time with it. @Hengky
    – Egypte
    Jun 10, 2020 at 15:40
  • @gNerb when creating similar code provided above, did you use numeric values to determine if there was a duplicate contained?
    – Egypte
    Jun 10, 2020 at 15:42
  • @Egypte Maybe add an empty string could solve the issue compositeKeys.add('' + co.asset__c + co.opportunity__c); } Jun 10, 2020 at 18:34
  • 1
    Just want to note here that I got it to work by removing the "trigger.new" from the trigger. Works perfectly. Thank you!
    – Egypte
    Jun 11, 2020 at 0:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .