3

So recently I got that error "Record ID: cannot specify Id in an insert call", and after doing some research I fixed it by.

try{                                  
            insert p;
}catch(exception e){
            Database.rollback(sp); 
            p = p.clone(false);
            system.debug('Broke');                                 
} 

What did I do? What exactly is going on here? Update**

This was my old test class

@isTest(SeeAllData=true)
private class AutoPopulateSampleTest {

static testMethod void rsmUpdate() {

    Product2 p = new Product2(id = '01tE0000000hVTcIAM',
    Name = 'Erics',
     AE2__c = '01tE0000000hNN1IAM',                    
     Country_code__c = 'USA' 
     );

    insert p;

    Sampling__c s = new Sampling__c(Quantity_of_Samples__c = 2,
    //s.Date_Sample_Needed__c = (2014,3,18),
    Product__c = '01tE0000000hNN1IAM',
    Override__c = 'No',
    Country__c = 'US',
    State_Province__c = 'CA',
    Zip_Postal_Code__c = '93003', 
    Contact__c = 'Boop Betty');

    insert s;


   try {
insert S;
} catch (DmlException e) {
system.assertEquals(true, e.getMessage().contains('my expected error'));
   }
 }
}

2 Answers 2

2

In the original constructor, you specified an ID for P. If your goal is to create a new product record (the ideal scenario), you should not specify an ID, since the ID will be provided to you upon the record being committed.

You also have a duplicate insert s, which would cause a DMLException, but not for the reason you're testing for. For P's PE2__c field, create a second product and link the first one to that one, or query one from the database if that's imperative (using SeeAllData=true, but that may prove unreliable).

Finally, you should avoid using SeeAllData=true when possible, because that does have a habit of causing unexpected failures (but, if you need certain standard data, like price book data, you can't avoid it). Instead, insert any new records you need to test your code; they'll be deleted afterwards.

1
  • Thanks for every ones help.. I'm going to have to start a new thread, this test class is testing me.
    – EricSSH
    Commented Mar 26, 2014 at 16:59
3

Answer to original question (without the "old test class")

This reads as if p already has an ID value set. An insert is not allowed in that case.

Was p queried from the database? Or cloned preserving the ID? Or created in memory with an ID set? Your clone call is discarding the ID and you will be inserting an entirely new database row.

Try/catch/rollback is not the right fix for a "cannot specify Id in an insert call" error.

If you have queried (so that your object has an ID) and want to save changes just use:

update p;

There is also this:

upsert p;

that will insert if there is no ID and will update if there is an ID. This might be useful in your case if for some reason it is unclear whether p has an ID or not.

In response to the "Update" in the question (the addition of the "old test class")

Its a bit hard to follow how the "was" and "is" fit together. I'm surprised that inserts of objects with hard coded Ids work at all; it is not something I have ever done. Perhaps the behaviour is affected by what is in the database which the test is exposed to by using SeeAllData=true.

Instead of hard coding Ids it is cleaner to create the objects in the test. (If that is not trivial then test fixture or builder classes can be created to do that work so that code can be shared between multiple tests.) Looking at your old test class it looks like one extra object (whose type I've represented as ????__c) is needed. If that is trivial to create, then the test could look like this (note no SeeAllData=true):

@isTest
private class AutoPopulateSampleTest {

    static testMethod void rsmUpdateResultsInError() {

        ????__c pp = new ????__c(...);
        insert pp;

        Product2 p = new Product2(
                Name = 'Erics',
                AE2__c = pp.Id,                    
                Country_code__c = 'USA' 
                );
        insert p;

        Sampling__c s = new Sampling__c(
                Quantity_of_Samples__c = 2,
                Product__c = pp.Id,
                Override__c = 'No',
                Country__c = 'US',
                State_Province__c = 'CA',
                Zip_Postal_Code__c = '93003', 
                Contact__c = 'Boop Betty'
                );
        try {
            insert s;
            System.assert(false, 'DmlException expected but not thrown');
        } catch (DmlException e) {
            System.assert(e.getMessage().contains('my expected error'), e.getMessage());
        }
    }
}

This test is isolated from data in any org it runs in and should not generate any "cannot specify Id in an insert call" errors.

4
  • Close... pp is obviously another Product2 (they both start with 01t), and there should be no surprise that you can specify an ID this way; it's a design feature. Of course, the code were migrated to another org, it would fail, because that ID wouldn't belong to that org (exception: full-data-copy sandboxes retain ID values from production).
    – sfdcfox
    Commented Mar 26, 2014 at 5:04
  • @sfdcfox The hard coded Id is don't understand is the "new Product2(id = '01tE0000000hVTcIAM'" one; how can hard coding such an Id and inserting ever work? Yeah didn't notice the common type value.
    – Keith C
    Commented Mar 26, 2014 at 8:48
  • With SeeAllData, the code doesn't fail as long as the ID either: (a) exists in the current database and the current user has sharing permission (if sharing is enabled), or (b) it is the magic ID '000000000000000AAA' (effectively a null ID).
    – sfdcfox
    Commented Mar 26, 2014 at 10:25
  • @sfdcfox Thanks. I was under the mistaken belief that no insert with an id set would work (on the grounds that that is really an update). Great to know about '000000000000000AAA'.
    – Keith C
    Commented Mar 26, 2014 at 10:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .