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');
                }
            }
    }

}
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 '20 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 '20 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 '20 at 15:42
  • @Egypte Maybe add an empty string could solve the issue compositeKeys.add('' + co.asset__c + co.opportunity__c); } – Hengky Ilawan Jun 10 '20 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 '20 at 0:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.