Development questions

Write a trigger on a custom junction object Project_Resource__c to prevent linking the same Contact to the same Project__c more than once.

Use before insert, before update on the junction object. Compare against existing junction records and others in the same batch using a Contact+Project key.

apex
trigger PRTrigger on Project_Resource__c (before insert, before update) {
    Set<Id> projects = new Set<Id>(), contacts = new Set<Id>();
    for (Project_Resource__c r : Trigger.new) { projects.add(r.Project__c); contacts.add(r.Contact__c); }
    Set<String> keys = new Set<String>();
    for (Project_Resource__c e : [SELECT Project__c, Contact__c FROM Project_Resource__c
                                  WHERE Project__c IN :projects AND Contact__c IN :contacts AND Id NOT IN :Trigger.new]) {
        keys.add(e.Project__c + '|' + e.Contact__c);
    }
    for (Project_Resource__c r : Trigger.new) {
        if (!keys.add(r.Project__c + '|' + r.Contact__c)) r.addError('This Contact is already linked to the Project.');
    }
}

A duplicate/unique text field (e.g. a formula-populated external key with Unique) is a declarative alternative.

apex-triggertriggercodingscenariojunctionduplicates