3

I want to replace the attachment Name (File Name) with the ParentName. So can I replace the attachment name?

I have written the trigger on attachment an object. But Trigger is not working because of parent.name field is accessible after the insertion of an attachment.

Please find the code below

trigger renameAttachment on Attachment (before insert) {

    Map<Id,String> Mapattachment = new Map<Id,String>();

    set<Id> objParentIds = new set<Id>();
    for(Attachment objAtt : Trigger.new){
        objParentIds.add(objAtt.ParentId);
    }

    for(Attachment objAttachment : [SELECT id,Name,ParentId,Parent.Name FROM Attachment WHERE ParentId IN:objParentIds]){
        Mapattachment.put(objAttachment.ParentId,objAttachment.Parent.Name);
    }

    system.debug('Mapattachment=====>'+Mapattachment);

    for(Attachment objAttachment : Trigger.new){
        if(Mapattachment.containsKey(objAttachment.ParentId)){
            objAttachment.Name = Mapattachment.get(objAttachment.ParentId);
        }
    }
}

2 Answers 2

2

In before Insert Trigger, you do not have ID and that record doesn't exists in the database, thus your querry [SELECT id,Name,ParentId,Parent.Name FROM Attachment WHERE ParentId IN:objParentIds] will fail.

The logic here is to let the insert happen, and in after insert trigger do a DML to update the name of attachment with that of parent's Name. Thus your logic or trigger should be after insert.

trigger renameAttachment on Attachment (after insert) {
    List<Attachment> toBeUpdatedAttachment = new List<Attachment>();
    for(Attachment objAttachment : [SELECT id,Name,ParentId,Parent.Name FROM Attachment WHERE Id IN:Trigger.new]){
                   objAttachment.Name = objAttachment.Parent.Name;
                   toBeUpdatedAttachment.add(objAttachment);

    }

      update toBeUpdatedAttachment;
 }
2
  • 1
    if(!toBeUpdatedAttachment.isEmpty()) is not necessary, and hasn't been for a few years.
    – sfdcfox
    Commented May 19, 2018 at 14:45
  • 1
    Technically speaking, since OP is not trying to gather or query the Ids of the Attachment record, but rather the Ids of the parent record (which are available before insert), the query does have a chance to return some rows (just not the rows being inserted). OP's approach would work for non-polymorphic relationships (like AccountId on Opportunity, provided that the query were on Account instead of Opportunity). Your solution (move to after insert and accept the need to perform a DML update) is still good and straightforward, so +1 from me.
    – Derek F
    Commented May 19, 2018 at 14:58
1

For all practical purposes, if you want do this in a before trigger, you need to directly query the parents. That would look something like this:

Set<SObjectType> types = new Set<SObjectType>();
Set<Id> recordIds = new Set<Id>();
for(Attachment record: Trigger.new) {
    types.add(record.ParentId.getSObjectType());
    recordIds.add(record.ParentId);
}
Map<Id, SObject> parents = new Map<Id, SObject>();
for(SObjectType objType: types) {
    parents.putAll(Database.query('SELECT Name FROM '+objType+' WHERE Id IN :recordIds'));
}
for(Attachment record: Trigger.new) {
    record.Name = parents.get(record.ParentId).get('Name');
}

In most normal cases, this is probably acceptable, but keep in mind that mass uploading attachments might result in too-many-soql errors. Also, if you want to handle Contract and Case parent records, keep in mind that those two objects have unique name fields.

In general, however, you might want to use a recursive update, like Pranay's solution, since it's less complicated.

You must log in to answer this question.

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