Before Insert Trigger Help With Delete

apexbefore-triggertrigger

I am creating a before insert trigger. This trigger will handle records being inserted and that part works correctly, however I am having problems with records I want to flag for deleting.

In this case there would already be a record in Salesforce that would be flagged with 'A', now a update to that record is coming in with 'X' and that is a flag to me that I want to delete that record. The below gets me to the point of updating the record from 'A' to 'X', but I am stuck on how I can get these records deleted. The delete statement always returns 0 records. I assume I am doing this wrong or in the wrong place. Any ideas?

trigger enrollTrigger on hed__Program_Enrollment__c (before insert) {
Set<String> toBeDeleted= new Set<String>();

for(hed__Program_Enrollment__c myEnroll: trigger.New) {
   if(myEnroll.flag == 'X') {
    // Flag this for delete
     toBeDeleted.add(myEnroll.id);
    }  else {
   // process the records to insert
   }

   delete [SELECT ID, NAME FROM hed__Program_Enrollment__c in : toBeDeleted];
   }

Just adding some more context. Basically this would be done in bulk from the data loader as an upsert. Some records are brand new and I want to insert them. Other records were good before and marked with 'A' and now they have been flagged with an 'X' so I would want to remove that current 'A' record.

Best Answer

You can't delete records before they're saved to the database (for lack of a better word), and that doesn't happen until just before an after insert trigger would fire.

Records being inserted are also not able to be queried until they are assigned an Id (which also happens just before an after insert trigger would fire).

If you're looking to handle situations where people are entering these records one at a time, then a validation rule would be a much better choice (stop bad data before it gets saved!).

If you're inserting these records from some other trigger or apex class, then you should be preventing the records you'd end up deleting from even attempting to be inserted in the first place.

e.g.

List<hed__Program_Enrollment__c> recordsToInsert = new List<hed__Program_Enrollment__c>();
for(SomeObject__c someRecord :[SELECT <some fields> FROM SomeObject__c WHERE <filters>]){
    hed__Program_Enrollment__c enrollment = createEnrollment(someRecord);

    if(enrollment.Flag__c = 'X'){
        // skip this record, and move on to the next iteration of the loop
        continue;
    }

    recordsToInsert.add(enrollment);
}

insert recordsToInsert;

+edit:

On a second reading, it seems like your records do not initially have this flag set to 'X', but that's happening in a separate update (through some process).

If that's the case, then you'd want to use the after update context to your trigger (you really should be using a trigger framework, but that's out of scope for your question), iterating through a trigger context variable to figure out which records should be deleted (adding them to a list), and then deleting them (no queries required).

Given your current trigger structure, such a trigger could look like

// Best practice is to have only a single trigger on any given object
// A single trigger can be run in different contexts by adding multiple contexts
//   inside the "()", separated with commas
trigger MyTrigger on MyObject__c (before insert, after update){
    // You can do specific work in each context by checking
    //   - Trigger.isBefore
    //   - Trigger.isAfter
    //   - Trigger.isInsert (or isUpdate, isDelete, isUndelete)
    //   - Trigger.operationType

    // Best practice is also to use a trigger framework and keep logic outside
    //   of the trigger itself.
    // I'm not going to go over that, but breaking your work into specific events
    //   like this will make that transition easier/more intuitive
    switch on Trigger.operationType{
        when System.TriggerOperation.BEFORE_INSERT{
            // do work to modify data before it's inserted so you can
            //   avoid needing to do a DML update
        }
        when System.TriggerOperation.AFTER_UPDATE{
            List<SObject> recordsToDelete = new List<SObject>();

            for(MyObject__c myRecord :trigger.new){
                if(myRecord.Flag__c == 'X'){
                    recordsToDelete.add(myRecord);
                }
            }

            delete recordsToDelete;
        }
    }
}