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, 2014 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, 2014 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, 2014 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, 2014 at 14:47

2 Answers 2

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, 2014 at 15:44
  • @user8746 have u created fields like apiName__c, User__c, ChangedBy__c, OldValue__c, NewValue__c
    – sfdc
    Jun 5, 2014 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, 2014 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, 2014 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, 2014 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, 2014 at 14:48

You must log in to answer this question.

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