+ Start a Discussion
AxxxVAxxxV 

Working with Attachments in Apex Code

I am trying to copy an attachment from one account to the other in Apex Code and receive the following compilation error: "Data type not supported".

I highlighted the line of code that generated the error. It lookslike Apex Code does not support the .Body datatype. Is there anyway to insert an Attachment in Apex?

Here is the snippet of my code:

Code:
for (Attachment attachmentSource : [Select Body, ContentType, IsPrivate, Name from Attachment where ParentId = :a.Clone_From_ID__c])
{
Attachment attachmentTarget = new Attachment();


attachmentTarget.ParentId = a.Id;
attachmentTarget.OwnerId = a.OwnerId; //assign same owner as parent account

attachmentTarget.Body = attachmentSource.Body;
attachmentTarget.ContentType = attachmentSource.ContentType;
attachmentTarget.IsPrivate = attachmentSource.IsPrivate;
attachmentTarget.Name = attachmentSource.Name;

insert(attachmentTarget);
}

 




Best Answer chosen by Admin (Salesforce Developers) 
AxxxVAxxxV

Here is an entire method from the application I wrote. This clones attachments in bulk from one object to another, plus does a few other things as part of the bigger application that it was a part of. But the relevant section of the code is in bold red.


Code:
 public CloneResult cloneAttachmentsInternal(Id idFrom, Id idTo)
{
CloneResult cr = new CloneResult();
cr.objectType = 'Attachment';

Map<Id, Id> idFromToResultMap = new Map<Id, Id>();

Integer recordCounter = 0;

for ( Attachment[] sourceAtts : [Select Id, Body, ContentType, IsPrivate, Name from Attachment where ParentId = :idFrom LIMIT :QUERY_LIMIT_FOR_ATTACHMENTS_AND_NOTES])
{
Attachment[] targetAtts = sourceAtts.deepClone(false); for(Attachment targetAtt : targetAtts){
targetAtt.ParentId = idTo;
recordCounter++;
}

insert targetAtts;
System.assertEquals(sourceAtts.size(), targetAtts.size(), 'Number of source objects is not equal to the number of cloned objects'); for(Integer i = 0; i<targetAtts.size(); i++){ if(idFromToResultMap.size() < COLLECTION_SIZE_LIMIT) idFromToResultMap.put(sourceAtts[i].Id, targetAtts[i].Id); else{ cr.clonedObjectsIdMap.add(convertIdMapInternaltoExternal(idFromToResultMap)); idFromToResultMap.clear(); idFromToResultMap.put(sourceAtts[i].Id, targetAtts[i].Id); } } } cr.size = recordCounter; cr.clonedObjectsIdMap.add(convertIdMapInternaltoExternal(idFromToResultMap)); cr.done = (recordCounter < QUERY_LIMIT_FOR_ATTACHMENTS_AND_NOTES) — true : false; return cr; }
 


Message Edited by AxxxV on 04-27-2008 03:30 PM

Message Edited by AxxxV on 04-27-2008 03:31 PM

All Answers

mtbclimbermtbclimber
No this is not possible. Apex Code does not currently support the Base64 datatype required for accessing the body of attachments, documents and scontrols.
ApprivoApprivo
Andrew,
Are there plans to support this at any time?

Cheers
Andrew.

mtbclimbermtbclimber
Yes, we are planning to support this in a future release.
mikeegarmikeegar
Any news on this feature? It would be very usefull for simple files like CSV.
AxxxVAxxxV
FYI: While this feature is not available I used a workaround with .clone() method....

Something like:

Attachment newAtt = oldAttachment.clone();
newAtt.ParentId = newParentId;
newAtt.Name = 'New Name';

If interested, let me know and will can post exact code. This approach works just as well.
mikeegarmikeegar
Hey Axxv,
    Thanks for the tip! I am looking more into parsing the content of the attachment. Have you had any luck in this area?

Thanks,

Mike
AxxxVAxxxV
No, that is not possible now as far as I know... 

Would be a good candidate for ithe deaExchange post. This would nicely go hand in hand with the upcoming Email-to-Apex functionality by the way... This way not only could we receive attachments in Apex, but also be able to parse them....
R()BbyR()Bby
Hi,

Are you sure the clone for attachments work?  I tried using the same but i always get an error: "Required fields are missing; Body".

It would be helpful if you can show me the complete code that you have.

What i want for my trigger is when a user deletes an attachment. It should create a clone of the attachment. Parent and Owner Id fields must be changed to a static Account and User.

Any help is very much appreciated.

Thanks,

R()Bby
AxxxVAxxxV

Here is an entire method from the application I wrote. This clones attachments in bulk from one object to another, plus does a few other things as part of the bigger application that it was a part of. But the relevant section of the code is in bold red.


Code:
 public CloneResult cloneAttachmentsInternal(Id idFrom, Id idTo)
{
CloneResult cr = new CloneResult();
cr.objectType = 'Attachment';

Map<Id, Id> idFromToResultMap = new Map<Id, Id>();

Integer recordCounter = 0;

for ( Attachment[] sourceAtts : [Select Id, Body, ContentType, IsPrivate, Name from Attachment where ParentId = :idFrom LIMIT :QUERY_LIMIT_FOR_ATTACHMENTS_AND_NOTES])
{
Attachment[] targetAtts = sourceAtts.deepClone(false); for(Attachment targetAtt : targetAtts){
targetAtt.ParentId = idTo;
recordCounter++;
}

insert targetAtts;
System.assertEquals(sourceAtts.size(), targetAtts.size(), 'Number of source objects is not equal to the number of cloned objects'); for(Integer i = 0; i<targetAtts.size(); i++){ if(idFromToResultMap.size() < COLLECTION_SIZE_LIMIT) idFromToResultMap.put(sourceAtts[i].Id, targetAtts[i].Id); else{ cr.clonedObjectsIdMap.add(convertIdMapInternaltoExternal(idFromToResultMap)); idFromToResultMap.clear(); idFromToResultMap.put(sourceAtts[i].Id, targetAtts[i].Id); } } } cr.size = recordCounter; cr.clonedObjectsIdMap.add(convertIdMapInternaltoExternal(idFromToResultMap)); cr.done = (recordCounter < QUERY_LIMIT_FOR_ATTACHMENTS_AND_NOTES) — true : false; return cr; }
 


Message Edited by AxxxV on 04-27-2008 03:30 PM

Message Edited by AxxxV on 04-27-2008 03:31 PM
This was selected as the best answer