[SalesForce] Content Document Link: FIELD_INTEGRITY_EXCEPTION, Document with ID: *** is already linked with the entity with ID: ***: Linked Entity ID:

I have a trigger on contentversion object which inserts contentdocumentlink to share files specific user whenever a new file is uploaded. If I try to upload a new version to already existing file, I get below error. Can someone help me resolve this.

Error: There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger ContentVersionTrigger caused an unexpected exception, contact your administrator: ContentVersionTrigger: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, Document with ID: 0693F000000Euj5 is already linked with the entity with ID: 005600000029OkF: Linked Entity ID: [LinkedEntityId]: Trigger.ContentVersionTrigger: line 17, column 1".

trigger ContentVersionTrigger on ContentVersion (after insert) {
    if(!TriggerRunOnce.hasAlreadyfired()){
        List<user> users = [select user.id, user.Email, user.FirstName, user.LastName, user.profile.name, user.Username, user.IsActive FROM user, user.profile where user.LastName IN ('***','***') and user.IsActive=true];
        List<ContentDocumentLink> ContentDocumentList = new List<ContentDocumentLink>();
        for(ContentVersion cv:trigger.new){
            system.debug('at 5 '+cv);
            if(cv.ContentDocumentId != null){
                for(user u:users){
                    if(u.Id != cv.OwnerId){
                        ContentDocumentLink cdl = new ContentDocumentLink(ContentDocumentId=cv.ContentDocumentId,LINKEDENTITYID = u.Id,SHARETYPE='C');
                        ContentDocumentList.add(cdl);  
                    }
                }
            }
        }

        insert ContentDocumentList;
        TriggerRunOnce.setAlreadyfired();
    }
}

Best Answer

You need to put a check to verify if ContentDocumentLink records exist before putting it into final list ContentDocumentList. Logic will be like this.

trigger ContentVersionTrigger on ContentVersion (after insert) {
    if(!TriggerRunOnce.hasAlreadyfired())
    {
        List<user> users = [select user.id, user.Email, user.FirstName, user.LastName, user.profile.name, user.Username, user.IsActive 
        FROM user, user.profile 
        where user.LastName IN ('***','***') and user.IsActive=true];
        Set<Id> contentDocumentIdSet = new Set<Id>();

        for(ContentVersion cv:trigger.new)
        {
            if(cv.ContentDocumentId != null)
            {
                contentDocumentIdSet.add(cv.ContentDocumentId);
            }
        }

        List<ContentDocumentLink> lstContentDocumentlink = [SELECT ContentDocumentId, LINKEDENTITYID 
                                                            FROM ContentDocumentLink WHERE ContentDocumentId IN:contentDocumentIdSet];


        List<ContentDocumentLink> ContentDocumentList = new List<ContentDocumentLink>();


        for(ContentVersion cv:trigger.new)
        {
            system.debug('at 5 '+cv);
            if(cv.ContentDocumentId != null && !lstContentDocumentlink.contains(cv.ContentDocumentId))
            {
                for(user u:users){
                    if(u.Id != cv.OwnerId){
                        ContentDocumentLink cdl = new ContentDocumentLink(ContentDocumentId=cv.ContentDocumentId,LINKEDENTITYID = u.Id,SHARETYPE='C');
                        ContentDocumentList.add(cdl);  
                    }
                }
            }
        }

        insert ContentDocumentList;
        TriggerRunOnce.setAlreadyfired();
    }
}