0

I wrote this apex trigger for Attachment sObject following the answer here. The trigger basically counts the total number of attachments for a record of type Assignment__c and updates the field Count_Attachment__c. But the trigger doesn't seem to be firing when I add a pdf file to the Notes and Attachments section in a record of custom object type Assignment__c. The Count_Attachment__c field isn't updated and I don't see anything in the logs in developer console. I'd googled and found an old issue with triggers on attachment object dating back to 2010. Is it still an issue?

trigger count_attachements on Attachment (after insert, after update, after delete, after undelete) {
    Set<Id> parentIdsSet = new Set<Id>(); //stores the parentids linked with modified attachments
    List<Attachment> attachmentList = new List<Attachment>(); //stores the list of modified attachments

    if (Trigger.new != null) {
        attachmentList.addAll(Trigger.new);
    } else if (Trigger.old != null){
        attachmentList.addAll(Trigger.old);
    }

    for (Attachment at: attachmentList) {
        parentIdsSet.add(at.ParentId);
    }

    parentIdsSet.remove(null);

    //stores mapping parentIds to total attachment count for that id
    Map<Id, Integer> objecttIdToAttachmentCount = new Map<Id, Integer>();

    for(AggregateResult ar: [SELECT count(Id) attachmentCount, parentId FROM Attachment WHERE parentId IN :parentIdsSet GROUP BY parentId]) {
        Id objId = (Id)ar.get('parentId');
        Integer count = (Integer)ar.get('attachmentCount');

        count = count == null ? 0 : count;
        objecttIdToAttachmentCount.put(objId, count);
    }

    //for cases where parentid's last attachment is deleted as the above SOQL query wont include the deleted attachments
    for(Id parentId: parentIdsSet) {
        if(!objecttIdToAttachmentCount.containsKey(parentId)) {
            objecttIdToAttachmentCount.put(parentId, 0);
        }
    }

    // not necessary but useful if multiple object types in the parent list    
    Map<String, String> sobjectNameToTargetField = new Map<String, String> {
        'Assignement__c' => 'Count_Attachment__c'
    };

    List<SObject> parentRecordsToUpdate = new List<SObject>();

    for (Id parentId: objecttIdToAttachmentCount.keySet()) {
        SObjectType currentType = parentId.getSObjectType();

        if(!sobjectNameToTargetField.containsKey(currentType.getDescribe().getName())) {
            continue;
        }

        SObject parent = currentType.newSObject();
        parent.put(sobjectNameToTargetField.get(currentType.getDescribe().getName()), objecttIdToAttachmentCount.get(parentId));

        parentRecordsToUpdate.add(parent);
    }

    parentRecordsToUpdate.sort();
    update parentRecordsToUpdate;

}
  • 2
    Highly recommend using a tool for declarative rollups like dlrs. No need to write your own. – Adrian Larson Jan 22 at 5:14
  • 1
    Is the file being added as a File (ContentDocument) or an Attachment? – Nick Cook Jan 22 at 5:25
  • @NickCook I'm adding it as an attachment in the 'Notes and Attachments' section – Aanchal Adhikari Jan 22 at 5:28
  • Are you using Lightning Experience? If so, Salesforce is creating Content objects, not Attachments, which are the older Classic type of file attachment. – David Reed Jan 22 at 11:28
  • @DavidReed Yes. So do you mean I should be using Content object to attach files to a record? – Aanchal Adhikari Jan 22 at 16:22
0

Your trigger is not executing because, as you mention in comments, you're using Lightning Experience. In Lightning Experience, files are attached using the Content system, which creates ContentDocument, ContentVersion, and ContentDocumentLink records. The ContentDocumentLink associates a record to its parent. No Attachment is created in Lightning Experience.

You'll need to write your trigger against ContentDocumentLink. I'd suggest getting started by reading through the SOAP API reference linked above. There are some interesting restrictions around how this object works, especially as to how you can perform queries against it.

  • Thanks for this info. I created an apex trigger for the ContentDocumentLink which is set to trigger after insert, after update, after delete and after undelete but the trigger only gets fired after insert but not after update or after delete. Though the documentation you linked above says that The ContentDocumentLink object supports triggers before and after these operations: insert, update, delete. Could you help? – Aanchal Adhikari Jan 23 at 7:50
  • Hi Aanchal, my guess is that what you're seeing is the trigger fires only on changes to the link object. It won't fire on changes to the attached file itself. – David Reed Jan 23 at 12:34
  • Ok I get it now. I found a discussion on the same topic and guess I'll have to write another trigger for the ContentDocument. So is it the 'ParentId' field that stores the Id of the parent record? The field description of the parentId in the docs is a bit confusing. – Aanchal Adhikari Jan 23 at 13:44
  • On ContentDocumentLink, it is LinkedEntityId. Remember also that ContentVersion is the object that actually is created when a new file version is added. There's a lot of complexity there so the best route will depend on exactly what you are aiming to do. – David Reed Jan 23 at 13:45
  • My goal is simply to display the total attachment counts in each assignment(custom object) records. Since, the attachment trigger won't work, I was expecting to write the whole logic in a single trigger for ContentDocumentLink, but I've realized I can't do that. I also noticed that apex trigger on ContentDocument object gets triggers on insert, update and delete but I dont know which field I should use to get the Id of the parent record. – Aanchal Adhikari Jan 23 at 16:22
1

There are two things that needs to be verified

  1. Please check if the API name of Assignment object is Assignement__c and not Assignment__c
  2. You need to set the ID attribute for the records which needs to be updated, without which you won't be able to update the record. Ideally, it should give you an exception unless you are catching that exception.

    SObject parent = currentType.newSObject(parentId);
    //SObject parent = currentType.newSObject();
    //parent.put('Id', parentId); //you can use this if you are using parameter less method to construct your object 
    parent.put(sobjectNameToTargetField.get(currentType.getDescribe().getName()), objecttIdToAttachmentCount.get(parentId));
    parentRecordsToUpdate.add(parent);
    
  • I know I did a spelling error here. But 'Assignement__c' is the correct API name of the Assignment object. – Aanchal Adhikari Jan 22 at 6:51
  • Also, event if this error had been the cause of the issue, I'm sure I would have been able to see something is the logs. – Aanchal Adhikari Jan 22 at 6:53
  • @Aanchal, I updated the answer, you missed to set the ID for the records that needs to be updated. – Vijay Ganji Jan 22 at 7:12
  • Oh yes. I forgot to set the parentId as parameter. instead of the newSObject() I was supposed to use the newInstance() but I keep gettig the error that the functio doesn't exist. – Aanchal Adhikari Jan 22 at 7:27
  • We don't have newInstance() method on sObjectType class, instead you can use other overloaded method, newSObject(ID) which takes ID as a parameter. I updated the answer, hope that helps ! – Vijay Ganji Jan 22 at 7:45

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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