5

So currently, I was curious on what is the best way to find out how many records have been modified after being queried.

So far, the only way I have found to do it is the following:

List<sObject> exampleObjectList = [SELECT Id, FieldToUpdate FROM Example__c];

Set<sObject> clonedSet = new Set<sObject>();

for(sObject example : exampleObjectList)
    clonedSet.Add(example.clone(true, true, true, true));

//Modify records in exampleObjectList   

clonedSet .RemoveAll(exampleObjectList);
//Gives you the amount of records that have been modified in that list
Integer sObjectsModifiedCount = clonedSet.size();

I am just curious if there is a more efficient way to accomplish this. What are the performance drawbacks to this if I were to add this in a trigger or something (mainly to have a count of records modified by a particular trigger class). Any thoughts?

Code Update

I was looking over some documentation for Lists and Sets to find out if I can do this in less steps. This led me to the following correction:

List<sObject> exampleObjectList = [SELECT Id, FieldToUpdate FROM Example__c];
Set<sObject> clonedSet = new Set<sObject>(exampleObjectList.deepClone(true, true, true));

//Perform operations on exampleObjectList

clonedSet.RemoveAll(exampleObjectList);
Integer sObjectsModifiedCount = clonedSet.size();
3
  • 2
    One question I have is... why? Instead of trying to determine which records have been modified in the list, why not just add the modified records in a separate list as you modify them? Commented Oct 2, 2014 at 9:13
  • Sometimes in trigger classes, they take the whole list/map and do the filtering in the class itself, rather than build the list in the trigger - which can be practical for large or complex filtering conditions. This is technically a less invasive way to determine how many records its actually modifying without going into the class itself. Although, it probably wouldn't be the most practical/efficient. However, I think this would be great for unit tests to determine if a class modifies only the records you know need modifying. Commented Oct 2, 2014 at 14:10
  • Curious how you ended up solving this. How did it go? Commented Nov 3, 2018 at 3:52

1 Answer 1

0

So the idea is to compare records at two points in a transaction, without needing visibility into what's happening between those two points. Cool!

The updated version of your code is the most efficient way I can see to get a count of changed records in that situation, but it only works if you know you're dealing with unique records. If you're starting from a database query, then you're good: every record will have its own Id. If the records don't have unique Ids yet -- as would be the case in a Before Insert trigger -- you wouldn't know for sure that the count would be correct.

Assume c1 and c2 should be two contact records, though both currently have the same last name as their only field value.

Contact c1 = new Contact(LastName = 'Smith');
Contact c2 = new Contact(LastName = 'Smith');

List<Contact> contacts = new List<Contact>{c1, c2};
Set<Contact> contactSet = new Set<Contact>();
contactSet.add(c1);
contactSet.add(c2);

system.debug(contactSet.size()); // this will return 1

In the code above, the size of the contactSet will be 1, since c1 and c2 appear to be identical.

As long as you know you're dealing with unique records, as you are in your example, it might be interesting to know more than just how many records have changed:

List<Contact> contacts = [SELECT Id, LastName FROM Contact LIMIT 2];

Map<Id, Contact> contactsMap = new Map<Id, Contact>();
contactsMap.put(contacts[0].Id, contacts[0]);
contactsMap.put(contacts[1].Id, contacts[1]);

List<Contact> clonedContacts = contactsMap.values().deepClone(true, true, true);  // (Preserve Id, Preserve Readonly Timestamps, Preserve Autonumber Values)

clonedContacts[0].LastName = 'New Name';

Map<Contact, Contact> oldValues_to_newValues = new Map<Contact, Contact>();

for(Contact withNewValues : clonedContacts){
    oldValues_to_newValues.put(contactsMap.get(withNewValues.Id), withNewValues);

}

String oldName = contacts[0].LastName;
String newName = oldValues_to_newValues.get(contacts[0]).LastName;

System.assertEquals(oldName, newName);  // will return false

For each record, you can now use the oldValues_to_newValues map to compare individual fields as you like.

You must log in to answer this question.

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