0

When a new user is created in Salesforce and matches a custom field named Role__c, I am trying to take a list of objectives__c and apply them to the user. I want to copy everything from the objective__c and create the same objective again, but with this user as the owner.

Can that be done? Here is a basic sample code that I have so far.

trigger insertTasks on User (after insert) {
// get list of users needed to assign
List<User> userList = [SELECT Name FROM User where Onboarding__c = true];
List<Objectives__c> masterList = [SELECT Id,Name,Duration__c,Minutes__c,OwnerId,URL__c, Week__c FROM Objectives__c];
List<Objectives__c> objList = new List<Objectives__c>();
//loop thru users in the users list created above.
for(User newUser : Trigger.new){
    //create new objectives
    Objectives__c obj = new Objectives__c();
        obj.Name = obj.Name;
        obj.Status__c = 'Not Started';
        
    objList.add(obj);
}

if(userList.size() > 0)
{
    // insert objectives into a list for the new users with the specified profile
    insert objList;
}

The goal is to have all of the fields that are populated in the masterList to be added to the user that has onboarding checked on the creation of the user.

I was able to get closer at this time but am now getting the error below:

First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Objectives__c, original object: User: []: Trigger.insertTasks: line 18, column 1

2
  • welcome to SFSE; We don't have enough information here - where is the master list of Objectives that you want to clone and assign to the user as owner? Side note: It is probably not the greatest idea to have a custom field called Role when SFDC uses the same label to mean the UserRole object. I suspect this requirement could be done in Flow
    – cropredy
    Commented Feb 12, 2021 at 0:08
  • @cropredy I added more detail to the original post. However, I would like to do this via a trigger if its possible. Commented Feb 12, 2021 at 0:21

1 Answer 1

0

Because this is a trigger on User (a setup object), you can't do any other DML on non-setup objects in the same transaction. So, you will need to delegate the work to an asynchronous transaction (either future or queueable)

So, your trigger looks like this:

trigger insertTasks on User (after insert) {
   new DelegatedUserSetup().setObjectives(
      [SELECT Id 
        FROM User 
        WHERE Onboarding__c = TRUE AND
              Id IN: Trigger.newMap.keySet() ]); // ensure only current trigger context
} 

and you create another class as an all purpose delegation of user setup that you can use for other use cases.

public class DelegatedUserSetup {
   void setObjectives(User[] users) {
     System.enqueueJob(new SetObjectivesAsQueueable(users));
   } 

public class SetObjectivesAsQueueable implements System.Queueable {
   User[] users; 
   SetObjectivesAsQueueable(User[] users) {this.users = users;}

   public void execute(System.QueueableContext qc) {
       Objectives__c[] masterObjectives = 
         [SELECT Id,Name,Duration__c,Minutes__c,OwnerId,URL__c, Week__c 
           FROM Objectives__c WHERE someField__c = 'MASTER'];

       Objectives__c[] assignedObjectives = new List<Objectives__c>();

       for(User u : this.users){ // every user gets ea masterObjective
         for (Objective__c masterObjective : masterObjectives) {
           assignedObjectives.add(new Objective__c (
              OwnerId = u.Id,  // assign to user
              Name = masterObjective.Name,
              Status__c = 'Not started',
              ... // other fields
              ));
    
         }
       }
       insert assignedObjectives;  // if none, no DML burnt
    }
}
}

Notes

  1. You need some way to differentiate the master objectives from the user-assigned objectives. I put in a placeholder for you
  2. There's a chance you could hit DML limits if the number of users * # master objectives exceeds the number of allowed DML rows per sync transaction
  3. I renamed variables to be more meaningful
  4. I haven't tested the code; there could be typos
  5. You might need to introduce a guard and retry mechanism if the enqueueJob fails
12
  • Thank you @cropredy, I am getting only getting two errors in the class at this time that mentions on line five its not expecting 'public' and also on line 5 that overriding implementation of global of public interface methods must be global. Commented Feb 12, 2021 at 12:24
  • I was able to resolve all errors associated with this but am not getting any entries created when they are all set to MASTER__c. Any thoughts? @cropredy Commented Feb 12, 2021 at 18:47
  • @AlexImperiale - oops, missed the public modifier on the execute() method; fixed above. Does your queueable class get passed any user records? does the query that retrieves master objectives return any rows?
    – cropredy
    Commented Feb 12, 2021 at 18:55
  • no worries, however, I am very new to this and am unsure of how to check what you specified above. Commented Feb 12, 2021 at 18:59
  • @AlexImperiale - debug log is your friend here; here is a Debug Trailhead to get you started
    – cropredy
    Commented Feb 12, 2021 at 19:03

You must log in to answer this question.

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