function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Jesus GJesus G 

Compare old / new values of 2 lists

Hello,

I am writing a class for the User object where I have 2 lists that collect the new and old values of the trigger. Would it be possible to compare the 2 values of the same record and perform an action only if it has changed? Please, notice I am not using Maps since the future annotation is needed:
 
@future
    public static void handleAfterUpdate(Set<Id> newUserIds, Set<Id> oldUserIds) { 
        List <Contact> contactsToUpdate = new List <Contact>();
        List<User> newUsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive FROM User WHERE Id IN :newUserIds];
		List<User> oldUsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive FROM User WHERE Id IN :oldUserIds];
        for (User currentUser : /* list of the records where the previous fields have changed */) {
        	Contact con = new Contact();
            con.Id = currentUser.ContactId;
            con.User_profile__c = currentUser.Profile.Name;
            con.User_username__c = currentUser.Username;
            con.Active_User__c = currentUser.IsActive;
            contactsToUpdate.add(con);
        }
        update contactsToUpdate;
    }

Thank you very much,
J
Best Answer chosen by Jesus G
Jesus GJesus G
I finally managed to solve the issue by creating a Set of the records that need to be updated in a before update trigger and then passing that Set to the future method in the class.

Trigger:
trigger AllUserTriggers on User (before update) {
    if(Trigger.isBefore && Trigger.isUpdate) {
        Set <Id> usersToUpdate = new Set <Id>();
        for (User u : trigger.new) {
            if (u.username != trigger.oldMap.get(u.Id).username) {
                User newUser = new User();
                newUser.Id = u.Id;
                usersToUpdate.add(newUser.Id);
            }    
    	}
		AllUserTriggersHandler.handleBeforeUpdate(usersToUpdate);
    }
}

Class:
public class AllUserTriggersHandler {
    @future
    public static void handleBeforeUpdate(Set<Id> UserIds) { 
        List <Contact> contactsToUpdate = new List <Contact>();
		List <User> UsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive FROM User WHERE Id IN :UserIds];
        for (User newUser: UsersList){
        	Contact con = new Contact();
            con.Id = newUser.ContactId;
            con.User_profile__c = newUser.Profile.Name;
            con.User_username__c = newUser.Username;
            con.Active_User__c = newUser.IsActive;
            contactsToUpdate.add(con);
        }
		update contactsToUpdate;
    }
}

All Answers

venkat-Dvenkat-D
Why are you using future method. if it is to avoid issue of standard and non standard update sequence. What you can do is create a new checkbox on user like CHANGED. In user trigger update that flag using comparison. then in the future method query those changed records and update contact accordingly.
Jesus GJesus G
Thank you for your answer.

I wanted to have everything in the class instead of part of the code in the trigger and part in the class, but I guess this is a good workaround in this scenario. I have tested it and it looks correct :)

The only thing I am having some issues with is to uncheck the checkbox after the records are updated so they are not included the next time the trigger is executed. Should I have that code in the trigger or the future class? (I have tried in both without success)

Many thanks,
J

 
venkat-Dvenkat-D
You should make it false for all records in context just before calculating the flag. That will ensure same records won't get updated again. Do this in trigger.
venkat-Dvenkat-D
In future method , just query records in context.
Jesus GJesus G
This is how my class looks now but the custom field 'changed__c' is not being unchecked:
@future
    public static void handleAfterUpdate(Set<Id> UserIds) { 
        List <Contact> contactsToUpdate = new List <Contact>();
		List <User> UsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive, Changed__c FROM User WHERE Changed__c = true AND Id IN :UserIds ];
        for (User newUser: UsersList){
        	Contact con = new Contact();
            con.Id = newUser.ContactId;
            con.User_profile__c = newUser.Profile.Name;
            con.User_username__c = newUser.Username;
            con.Active_User__c = newUser.IsActive;
            contactsToUpdate.add(con);
        }
		update contactsToUpdate;
        
		List <User> usersToUncheckList = new List <User>();
        for (User u : UsersList) {
			User userToUncheck = new User();
			userToUncheck.Id = u.Id;
			userToUncheck.changed__c = FALSE;
            usersToUncheckList.add(userToUncheck);
       	} 
        update usersToUncheckList;
    }
Thank you,
J
venkat-Dvenkat-D
You dont necessarily have to update user check box in future mothod. In the user trigger make sure you check true for required records and 
List <User> UsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive, Changed__cFROM User WHERE Changed__c = true AND Id IN :UserIds ];
above query will query only records that needs to be updated
Jesus GJesus G
I finally managed to solve the issue by creating a Set of the records that need to be updated in a before update trigger and then passing that Set to the future method in the class.

Trigger:
trigger AllUserTriggers on User (before update) {
    if(Trigger.isBefore && Trigger.isUpdate) {
        Set <Id> usersToUpdate = new Set <Id>();
        for (User u : trigger.new) {
            if (u.username != trigger.oldMap.get(u.Id).username) {
                User newUser = new User();
                newUser.Id = u.Id;
                usersToUpdate.add(newUser.Id);
            }    
    	}
		AllUserTriggersHandler.handleBeforeUpdate(usersToUpdate);
    }
}

Class:
public class AllUserTriggersHandler {
    @future
    public static void handleBeforeUpdate(Set<Id> UserIds) { 
        List <Contact> contactsToUpdate = new List <Contact>();
		List <User> UsersList = [SELECT Id, ContactId, Profile.Name, Username, IsActive FROM User WHERE Id IN :UserIds];
        for (User newUser: UsersList){
        	Contact con = new Contact();
            con.Id = newUser.ContactId;
            con.User_profile__c = newUser.Profile.Name;
            con.User_username__c = newUser.Username;
            con.Active_User__c = newUser.IsActive;
            contactsToUpdate.add(con);
        }
		update contactsToUpdate;
    }
}
This was selected as the best answer