[SalesForce] Why have database rows not been inserted when the debug log says they have

I have code that creates CaseShare records for the case based on some criteria from another class.

The code that creates the CaseShare is called both on update and creation of the case. It works smoothly when the case is updated, but not when it's created. When attempting to debug my issue I got confused because the debug logs apparently showed that the records were being inserted. In fact, the debug logs show the same exact things for when the case is inserted (the DML doesn't work then) as when the case is updated (the DML does work then).

Here is the debug log for both when the case is created (DML doesn't work then) and when the case is updated (DML does work) line 55 is where my insert is happening:

14:14:54.417 (656673502)|USER_DEBUG|[55]|DEBUG|Value of csShareList: (CaseShare:{CaseAccessLevel=Edit, CaseId=500180000050HSWAA2, UserOrGroupId=005E0000004JDY4IAO}, CaseShare:{CaseAccessLevel=Edit, CaseId=500180000050HSWAA2, UserOrGroupId=005E0000000dNNWIA2}, CaseShare:{CaseAccessLevel=Edit, CaseId=500180000050HSWAA2, UserOrGroupId=005E0000000dBqjIAE}, CaseShare:{CaseAccessLevel=Edit, CaseId=500180000050HSWAA2, UserOrGroupId=005E0000005aSlXIAU})
14:14:54.417 (656680026)|SYSTEM_METHOD_EXIT|[55]|System.debug(ANY)
14:14:54.417 (656682834)|STATEMENT_EXECUTE|[56]
14:14:54.417 (656754459)|DML_BEGIN|[56]|Op:Insert|Type:CaseShare|Rows:4
14:14:54.417 (656778446)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:20
14:14:54.417 (717863949)|DML_END|[56]

Additionally, here's the code that does the insert:

if (!csShareList.isEmpty()){

            try{ 
                System.debug('Value of csShareList: ' + csShareList);
                insert csShareList;
            }
            catch(exception e){

                system.debug('Value of e.getMessage: ' + e.getMessage());

            }

        }

I checked to see whether or not the CaseShare has been inserted in three ways:

  1. By querying the CaseShares related to the case I just inserted.
  2. I pressed the "Sharing" button on the case record to view the case shares
  3. I tried to view the record as one of the users I attempted to share it with

On create, the query shows no CaseShare records with the users the code is sharing with, the sharing button also shows no CaseShare records with the users the code is sharing with, and the user gets insufficient access when trying to access the record.

However, upon edit, the query shows the CaseShare records with the users the code is sharing with, the sharing button also shows the CaseShare records with the users the code is sharing with, and the user gets is able to view the record when trying to access the it.

EDIT:
Thanks to the answer given by the Salesforce Fox I started looking into the owner and now have an answer to the question. The owner in my case was a queue.

Best Answer

One of your share entries is failing to insert, causing the entire DML to go through the exception handler. Odds are, you're trying to insert a share for the case owner, which isn't allowed. Here's the POC I wrote that demonstrates this:

trigger Cases on Case (after insert, after update) {
    User testUser = [SELECT Id FROM User WHERE Name = 'test user'];
    CaseShare[] shares = new CaseShare[0];
    for(Case record: Trigger.new) {
        shares.add(new CaseShare(CaseId=record.id, UserOrGroupId=testUser.Id, CaseAccessLevel='edit'));
    }
    insert shares;
}

Throw this code into a developer edition or spare sandbox, and make sure you have a single user that is named 'Test User' (first name Test, last name User), and try to change the owner to this user, and you'll come across a rather <sarcasm>specific</sarcasm> exception:

System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []

If you try manually assigning a share to the case owner, you get the usual, friendly error message:

Error: Cannot manually share to the record owner.

Personally, I'd go with simply allowing any partial update to succeed instead of using the harsh all-or-none mechanism:

Database.insert(csShareList, false);

Duplicate shares are acceptable, as insert operations on share records are actually automatically upserts instead (they update a matching existing row when possible).

Related Topic