You need to sign in to do that
Don't have an account?
Create and Associate Salesforce File Using Apex
Hello,
I'm creating an Apex class that creates a Salesforce File record and associates it with a parent record. I'm having a problem creating the association (ContentDocumentLink) record.
Here is what I'm doing:
Does anyone know what I'm doing wrong, not considering, etc?
Appreciate any thoughts and input!
I'm creating an Apex class that creates a Salesforce File record and associates it with a parent record. I'm having a problem creating the association (ContentDocumentLink) record.
Here is what I'm doing:
- Create a ContentVersion record. This creates a ContentDocument record automatically if you leave the ContentVersion.ContentDocumentId field blank. (https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_contentdocument.htm - "To create a document, create a new version via the ContentVersion object without setting the ContentDocumentId. This automatically creates a parent document record.")
- Insert ContentVersion record
- DEBUG: Confirm ContentVersion.ContentDocumentId is set (Here is where the problem is because it is NULL; however if I SOQL query ContentVersion after the Apex completes, ContentVersion.ContentDocumentId is set and the corresponding ContentDocument record exists)
- Create ContentDocumentLink record (commented out because it fails because ContentDocumentLink.ContentDocumentId is a required field)
- Insert ContentDocumentLink record (commented out because it fails because ContentDocumentLink.ContentDocumentId is a required field)
public class FileController { @AuraEnabled public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType, Id contentDocumentId) { base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8'); ContentVersion cv = new ContentVersion(); cv.ContentLocation = 'S'; cv.ContentDocumentId = contentDocumentId; cv.VersionData = EncodingUtil.base64Decode(base64Data); cv.Title = fileName; cv.PathOnClient = filename; insert cv; //***This DEBUG statement must return an Id for the rest of the code to work*** System.debug('contentDocumentId='+cv.ContentDocumentId); //ContentDocumentLink cdl = new ContentDocumentLink(); //cdl.ContentDocumentId = cv.ContentDocumentId; //cdl.LinkedEntityId = parentId; //cdl.ShareType = 'I'; //insert cdl; return cv.Id; } @AuraEnabled public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) { return saveTheFile(parentId, fileName, base64Data, contentType, NULL); } }
Does anyone know what I'm doing wrong, not considering, etc?
Appreciate any thoughts and input!
Well the culprit in your code is the null value and way you are using it to assign the value to ContentDocumentLink.contentDocumentId.
You should query the content version object again to get the contentDocumentId (which is generated after the parent document is inserted by default because of you passing of null value).
Something like below :
As per the salesforce documentation lines higlighted by you, "To create a document, create a new version via the ContentVersion object without setting the ContentDocumentId. This automatically creates a parent document record." it does create the parent document record as expected, but the contentDocumentId is still null in above initialised object. Id doesn't get updated automatically to the object instance. Infact you will have to pull out the corresponding Id as done in the above snippet.
Let me know if this helps.
All Answers
Well the culprit in your code is the null value and way you are using it to assign the value to ContentDocumentLink.contentDocumentId.
You should query the content version object again to get the contentDocumentId (which is generated after the parent document is inserted by default because of you passing of null value).
Something like below :
As per the salesforce documentation lines higlighted by you, "To create a document, create a new version via the ContentVersion object without setting the ContentDocumentId. This automatically creates a parent document record." it does create the parent document record as expected, but the contentDocumentId is still null in above initialised object. Id doesn't get updated automatically to the object instance. Infact you will have to pull out the corresponding Id as done in the above snippet.
Let me know if this helps.
I still wonder why I wasn't able to access the cv.ContentDucmentId after insert cv; perhaps the automatic creation of the ContentDocument record happens asyncronously, in which case the SOQL query assignment you described may also fail sometimes. I should handle that possiblity in a try catch block.
Thanks again!
To explain the behaviour, take it this way. Since salesforce follows an MVC framework(Model = Object, View = VF pages, Controller = Apex Classes).
In your class i.e., the controller, send the request to the Model(database) to create ContentVersion record, the record gets created and an Id is generated and associated to it. ThisId creation and association is done at the Model (database) level only. Your Controller doesn't know what this Id is, so to get this Id we again make a query to the Model(database) level to extract it and use it.
I'm not sure if this made things more clear or confused you more.. :)
To create a ContentVersion record and automatically create a ContentDocument record, you can use the following Apex code:
ContentVersion cv = new ContentVersion();
cv.Title = 'Test Document';
cv.PathOnClient = 'test.pdf';
cv.VersionData = Blob.valueOf('Test document content');
insert cv;
System.debug('ContentVersion.ContentDocumentId: ' + cv.ContentDocumentId);
// Create ContentDocumentLink record
// ContentDocumentLink cdl = new ContentDocumentLink();
// cdl.ContentDocumentId = cv.ContentDocumentId;
// cdl.LinkedEntityId = '<ID of related object>';
// cdl.ShareType = 'V';
// insert cdl;
It is important to note that after inserting the ContentVersion record, you will need to query it again to retrieve the ContentDocumentId, as it is not immediately available after the insert. You can then use the ContentDocumentId to create a ContentDocumentLink record (https://quotesjin.com/), linking the newly created ContentDocument to a related object, such as a Contact (https://nadiakvk.org/) or an Account.