5

After extensive research I think I know what I need to do, but I don’t know how to get there

basically, I need to create a trigger to determine when a field was last populated.

I know this can be done via workflow and using the now() function for eg, if field is changed populate with date. However I have over 50 fields per object so don’t want to great 50 new date/time fields.

Now my idea is to Create a new object called “Analysis” and have the following three fields “Object Name”, “field” , “Last Populated ”. (Not sure whether to use api name or field name)

For eg (If this field was last populated four days ago and trigger run today) Object Name = Account Field Name = Agent Code Api Name = Agent_Code__c Last Populated = 01/06/2014

For eg (If this field was last today and trigger run today) Object Name = Account Field Name = Agent Code Api Name = Agent_Code__c Last Populated = 05/06/2014

4
  • 2
    Do you really need it for all 50 fields ? And, have you looked into field-history-tracking ? Jun 5 '14 at 14:36
  • @SamuelDeRycke History Tracking is only for up to 20 fields, so that may not help in this case, although that'd be my first recommendation, too.
    – sfdcfox
    Jun 5 '14 at 14:38
  • 1
    That is why i asked if he needs 50 fields. I do believe salesforce can increase that limit .. if you have good arguments. Jun 5 '14 at 14:44
  • Hi, Field history only for 20 fields, and we have 50 + per object , so enabling field history wouldnt be viable option
    – user8746
    Jun 5 '14 at 14:47
1

Create an object called AccountHistoryTracking with fields like APIName__c, OldValue__c, NewValue__c, then create a fieldset on Account called 'HistoryTracking' with the fields you want to track on Account, and then write below code to track history on Account:

trigger AccountHistoryTracker on Account (after insert,after update) {
    List<Schema.FieldSetMember> trackedFields = SObjectType.Account.FieldSets.HistoryTracking.getFields();
    if (trackedFields.isEmpty()) return;

    List<AccountHistoryTracking__c> fieldChanges = new List<AccountHistoryTracking__c>();

    List<String> apiNameList = new List<String>();        

    if(Trigger.isUpdate){
        for (Account aNew : trigger.new) {

            Account aOld = trigger.oldmap.get(aNew.Id);

            for (Schema.FieldSetMember fsm : trackedFields) {

                String fieldName  = fsm.getFieldPath();
                String fieldLabel = fsm.getLabel();

                if (aNew.get(fieldName) != aOld.get(fieldName)) {

                    String oldValue = String.valueOf(aOld.get(fieldName));
                    String newValue = String.valueOf(aNew.get(fieldName));
                    if (oldValue != null && oldValue.length()>255) oldValue = oldValue.subString(0,255);
                    if (newValue != null && newValue.length()>255) newValue = newValue.subString(0,255); 

                    AccountHistoryTracking__c aht = new AccountHistoryTracking__c();
                    aht.name         = fieldLabel;
                    aht.apiName__c   = fieldName;
                    aht.User__c      = aNew.Id;
                    aht.ChangedBy__c = UserInfo.getUserId();
                    aht.OldValue__c  = oldValue;
                    aht.NewValue__c  = newValue;

                    apiNameList.add(aht.apiName__c);
                    fieldChanges.add(aht);

                }        

            }

        }

        List<AccountHistoryTracking__c> ahtToDelete = [select Id,apiName__c from AccountHistoryTracking__c where apiName__c in:apiNameList];

        if(ahtToDelete.size()>0){
            delete ahtToDelete;
        }
    }

    if(Trigger.isInsert){
        for (Account aNew : trigger.new) {
            for (Schema.FieldSetMember fsm : trackedFields) {

                String fieldName  = fsm.getFieldPath();
                String fieldLabel = fsm.getLabel(); 
                String newValue = String.valueOf(aNew.get(fieldName));
                if (newValue != null && newValue.length()>255) newValue = newValue.subString(0,255); 
                AccountHistoryTracking__c aht = new AccountHistoryTracking__c();
                aht.name         = fieldLabel;
                aht.apiName__c   = fieldName;
                aht.User__c      = aNew.Id;
                aht.ChangedBy__c = UserInfo.getUserId();
                aht.NewValue__c  = newValue;

                apiNameList.add(aht.apiName__c);
                fieldChanges.add(aht);

            }
        }
    }

    if (!fieldChanges.isEmpty()) {
        insert fieldChanges;
    }
}
14
  • Hi Sf.Dev I have a developer org login.salesforce.com/?lt=de I have created the object AccountHistoryTracking But i am now confused, is it possible if you could log in and have a look ?
    – user8746
    Jun 5 '14 at 15:44
  • @user8746 have u created fields like apiName__c, User__c, ChangedBy__c, OldValue__c, NewValue__c
    – sfdc
    Jun 5 '14 at 19:38
  • @ Sf dev. I cant sign in into my account when at work, so it registered me as user8746. yes all those fields are created, and the trigger created. However what i have noticed, if i update any field more than once it it shows in the report. For eg. i updated website from hotmail to yahoo to google, and i have 3 records . I ideally want to see one record. and that be the latest one
    – Masond3
    Jun 5 '14 at 19:45
  • @Masond3 you mean to delete the old field history record and create new field history record everytime field changes
    – sfdc
    Jun 5 '14 at 19:54
  • @sf dev - Yes. i should have one record per field. so if i have 50 fields per object i would expect 50 records in the report
    – Masond3
    Jun 5 '14 at 20:03
3

You have 2 options:

1) Enable field history tracking.

2) Create a trigger that uses the Schema to loop through every field on an object.

Map<String, Schema.SObjectField> auditQuestion_map = Schema.getGlobalDescribe().get('ObjectName__c).getDescribe().fields.getMap();

I suggest using option 1, but if for some reason it doesn't fulfill your needs you can fall back on option 2.

EDIT:

Do your normal loop through trigger.new and then inside that another loop over the fields. This should give you a general basis.

List<Tracking_Obj> tracking = new List<Tracking_Obj>();
for (SObject someObj: Trigger.new)
{
  SObject old = Trigger.oldMap.get(someObj.Id);
  for (Schema.SObjectField field: Schema.getGlobalDescribe().get('ObjectName__c).getDescribe().fields.getMap())
  {
    //I don't remember the exact syntax, but you can look up the API for that
    if (someObj.get(field.Name) != old.get(field.Name)
      tracking.add(new TrackingObj(Name = field.Name));
  }
}
1
  • 1
    Dphil Can you explain to me how option 2 works ?
    – user8746
    Jun 5 '14 at 14:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.