0

I have written the following Apex trigger:

trigger FeedThis on FeedComment(after insert, after update){

    List<Case> updates = new List<case>();
    List<id> userList = new List<ID>();
    List<Id> feedItemList = new List<id>();
    for(FeedComment fc: trigger.new){
        feedItemList.add(fc.FeedItemId);
        userList.add(fc.InsertedById);
    }
    Map<Id, FeedItem> feedMap = new Map<id, FeedItem>([select id,InsertedById,Visibility from feedItem where Id IN :feedItemList]);
    Map<Id, User> userMap = new Map<Id, User>([SELECT Id FROM User WHERE Support_Team_Member__c = true]);
    for(FeedComment fc: trigger.new){
        if (feedMap != null && feedMap.containsKey(fc.feedItemId) && fc.ParentId.getSObjectType() == Case.SObjectType) {
            updates.add(new Case(
                Last_Chatter_Feed_Timestamp__c = System.now()
            ));
            Case c = [SELECT ID, Case_Assigned_To_Support__c, Support_First_response_minutes__c FROM CASE WHERE ID =: fc.ParentId];
            if(userMap.containsKey(fc.InsertedById) && c.Support_First_response_minutes__c == null && c.Case_Assigned_To_Support__c != null && c.id != null){
                long totalMs =  DateTime.now().getTime() - c.Case_Assigned_To_Support__c.getTime();
                totalMs *= 60000;
                updates.add(new Case(
                    id = c.id,
                    Support_First_response_minutes__c = totalMs
                ));
            }
        }    
    }
    update updates;
}

My test is just a hacky catchall (or in this case catch 78%)

@isTest
private class TestFeedThis {
    @isTest static void updateTimestampWithChatter(){
        //Create a new test case
        Account a = new Account(name='test acc',phone='7777777777');
        insert a;
        Contact con = new Contact(accountid=a.id,email='test@test.com');
        con.FirstName = 'Testy';
        con.LastName = 'mcTest';
        insert con;
        Case testCase = new Case(Status = 'New', Priority = 'Medium', Description = 'Test', Last_Updated_By_Support__c = System.now(), Contact = con );
        insert testCase ;
        //Create a new feed item (Post) on the test case
        Feeditem fi = new feeditem();
        fi.Body = 'test Post on case';
        fi.Type = 'TextPost';
        //Create a new comment on the post in the case
        fi.ParentId = testCase.Id;
        insert fi ;
        FeedComment fc = new FeedComment(CommentBody = 'test', FeedItemID = fi.Id);
        fc.CommentType = 'TextComment';
        insert fc ;
    }
}

When I execute the test I'm getting the following error:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, FeedThis: execution of AfterInsert

caused by: System.DmlException: Update failed. First exception on row 0; first error: MISSING_ARGUMENT, Id not specified in an update call: []

Trigger.FeedThis: line 28, column 1: []

I've tried to fix this for the past 3 hours any help would be greatly appreciated.

2

The issue in your trigger is that something inside of the updates list isn't being given an Id.

Looking at your code, this section appears to be responsible:

for(FeedComment fc: trigger.new){
    if (feedMap != null && feedMap.containsKey(fc.feedItemId) && fc.ParentId.getSObjectType() == Case.SObjectType) {
        updates.add(new Case(
            Last_Chatter_Feed_Timestamp__c = System.now()
        ));

It's hard to say whether or not you should get rid of adding this particular Case to your list of Cases to update without knowing a bit more of the context, but it's clearly not being used in the trigger you've provided.

Your options here are:

  • Get rid of the troublesome code
  • Merge this bit (setting Last Chatter Feed Timestamp) with the other bit of code where you're putting a new Case into updates
  • Change your update to an upsert

Adding an Id to the troublesome bit of code won't work here (at least not without other changes) because you'd be using fc.ParentId, which is the same as the Id of the Case that you're querying (the query should be moved out of the loop). If you tried that, you'd get a duplicate Id in list error.

  • 1
    Also, I'd be remiss if I didn't mention that your test method should include assertions to validate that the changes/updates that your trigger is supposed to be doing are actually happening. That's not the immediate issue, but it is important. – Derek F Nov 13 at 21:00
1

Your immediate issue is this bit:

        updates.add(new Case(
        Last_Chatter_Feed_Timestamp__c = System.now()
    ));

where you are adding a new Case record, with only a single field populated, to the updates list. When you then get to:

update updates;

Salesforce says that it can't update records for which it doesn't have an Id. You also have a SQL query in a loop, which is a very bad idea:

Case c = [SELECT ID, Case_Assigned_To_Support__c, Support_First_response_minutes__c FROM CASE WHERE ID =: fc.ParentId];

You need to move your query for Case out of your loop. Add a list of Case Ids to your initial set of variable declarations, and then in your first loop over trigger.new, add ParentIds if they're Cases, and then query (including Last_Chatter_Feed_Timestamp__c) a map of <Id,Case> to use in your second loop.

I didn't look closely enough to figure out if all Cases that have FeedItems in the trigger will need to be updated, in which case you can just make the updates in the Map, and then update the Map's values. But if it's only some Cases, you should add those cases to the updates list and still update just that List.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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