1

This is the reference for this code :http://bobbuzzard.blogspot.co.nz/2012/03/create-parent-and-child-records-in-one.html

What exactly happens behind the scenes,when we say

Account acc=new Account(Name='Blog Acc 901', Master_Id__c='Blog Acc 9001');
Contact cont=new Contact(FirstName='Bob901', LastName='Buzzard', Account=new Account(Master_Id__c='Blog Acc 9001'));

Master_id__c is the external field.I understand specifying external id at somepoint helps to find it is pointing to acc.(like we specify external ids,instead of ids in dataloader) My main doubts are

*-what exactly is getting saved in Account foreign key reference field in Contact? is it the Database memory location for that record?

*In this particular eg: when we say Account = new Account(Master_ID__C = 'abcd') ,what exactly is happening in heap memory and at what point does it realise it is pointing to acc

*Is external id,the only type of field that can be specified in this scenario?

3 Answers 3

4

What exactly happens behind the scenes,when we say

Account acc=new Account(Name='Blog Acc 901', Master_Id__c='Blog Acc 9001');
Contact cont=new Contact(FirstName='Bob901', LastName='Buzzard', Account=new Account(Master_Id__c='Blog Acc 9001'));

We are specifying three objects to be created in memory. The first is an account (acc), the second is a contact (cont), and the third is another account (cont.account).

...

*-what exactly is getting saved in Account foreign key reference field in Contact? is it the Database memory location for that record?

It's a normal memory reference to a heap location. Every object occupies memory on the heap, and so therefore each usage of the word new creates a new object on the heap. Imagine the heap looks like this after running those three lines of code:

Address Class           Data
0x0001  Schema.Account  Name='Blog Acc 901', Master_Id__c='Blog Acc 901'
0x0002  Schema.Account  Master_Id__c='Blog Acc 901'
0x0003  Schema.Contact  FirstName='Bob901', LastName='Buzzard', Account=0x0003

*In this particular eg: when we say Account = new Account(Master_ID__C = 'abcd') ,what exactly is happening in heap memory and at what point does it realise it is pointing to acc

Let's be clear: Cont.Account (0x0002) is not acc (0x0001), and the two references never point to the same heap address, even after inserting the new records. You can prove this by checking that System.assert(acc!==cont.account).

At no point in the data execution (in this scenario) does Apex Code "realize" that cont.Account is pointing to acc, because Apex Code considers them two discrete memory objects, even if they are literally "pointing" to the same database record.

The database itself knows that an External ID can be used to reference a record manually without an ID, and so when it encounters the Master_ID__c value, it is intelligent enough to consult the External ID index and acquire the appropriate ID for the given record.

*Is external id,the only type of field that can be specified in this scenario?

You can specify any field you want to, but only the External ID value will be considered for determining the correct record ID to use. This is useful for certain kinds of constructs where you want to be able to reference the related object later without a map. Here's an example trigger that utilizes this method:

trigger createSalesOpp on Order__c (before insert, after insert) {
    Opportunity[] newOpps = new Opportunity[0];
    if(Trigger.isBefore) {
        for(Order__c record:Trigger.new) {
            record.Opportunity__r = new Opportunity(AccountId=record.Account__c, StageName=Info.DefaultOpportunityStage, CloseDate=Info.DefaultCloseDate, Name='Holding Opp');
            newOpps.add(record.Opportunity__r);
        }
        insert newOpps;
        for(Order__c record:Trigger.new) {
            record.Opportunity__c = record.Opportunity__r.Id;
        }
    } else {
        for(Order__c record:Trigger.new) {
            newOpps.add(new Opportunity(Id=record.Opportunity__c,Name='Order '+record.Name));
        }
        update newOpps;
    }
}

We are creating a new order, either from the UI or data loader. We want to report to the funnel, so we backfill an opportunity. We do this in four steps:

  1. Create records in memory for each opportunity.
  2. Insert the opportunities.
  3. Copy the successful ID values back to the order.
  4. Rename the opportunity to match the order name.

Steps 1-3 occur in the before insert event, so Trigger.newMap has no keys, because the records have not yet been assigned an ID. In this case, we use the relationship as a storage device to temporarily associate the opportunity to the order long enough for us to create the record.

Step 4 occurs in the after insert event, so we now know what the ID for each Order is, and its auto-number value. We didn't know this initially, so we couldn't have specified this when creating the opportunity, but we wanted to store the data back in the order, which we couldn't have done in the after insert event, because the records would already be read-only.

In this way, you can use the mechanism as temporary storage, but you must remember to save the data somewhere permanent if you need to know this data later, because the association would disappear when the trigger ends.

0

*-what exactly is getting saved in Account foreign key reference field in Contact? is it the Database memory location for that record?

Salesforce will look for an account with Account.Master_Id__c = 'Blog Acc 901' and if found will set it's id into Contact.AccountId. If one isn't found you'll get an error.

*In this particular eg: when we say Account = new Account(Master_ID__C = 'abcd') ,what exactly is happening in heap memory and at what point does it realise it is pointing to acc

Not exactly sure what you're asking here.

*Is external id,the only type of field that can be specified in this scenario?

If you're looking to link a child record to a parent record using an external id to identify the parent record, yes, the field must be a parent id.

For example, assume the account has a name 'Hello', this would not change the name to 'World'

update new Contact(account = new Account(Master_Id__c = '123', Name = 'World'));

However you can put stuff into relationship fields to simplify display. For example

Contact c = new Contact();
system.debug(c.account.name); // -> null
c.account = new Account(name = 'Test');
system.debug(c.account.name); // -> 'Test'
-1

what exactly is getting saved in Account foreign key reference field in Contact? is it the Database memory location for that record?

When you define a new Contact, nothing is yet saved. If you insert or upsert the Contact cont in the database, then the data gets stored. Contact will likely store the Account Id field as a foreign key, even though the actual mechanism is abstracted away from you as the platform user.

Edit:

One has to first insert the Account. When inserting the Contact, the new Account(field=value,...) expression has to contain either an External ID or an indexed field through which the previously inserted account is found*.

In this particular eg: when we say Account = new Account(Master_ID__C = 'abcd') ,what exactly is happening in heap memory and at what point does it realise it is pointing to acc

Salesforce abstract the internals from you. It is very hard to know what is happening in the heap memory. However, one has a guarantee that after insertion, the Account will be stored and a Contact will be stored as well. The Contact will link to the stored Account through its id.

Is external id, the only type of field that can be specified in this scenario

The simplified syntax is (fieldName = <expression>, ...). You can put anything in the expression, but it has to be of the correct type for the fieldName in question. Fields that are relations to other Salesforce objects are an exception - you can also input an instance of that object type. If the instance has either an External ID or an indexed field filled, and a previously inserted object of that type exists with the same-valued fields, it will be automatically linked.

4
  • Inserting cont first won't generate an account. You'll get an error. Heap isn't as abstract as you think. It's very easy for one to prove if X references the same heap memory as Y.
    – sfdcfox
    Commented Sep 2, 2013 at 7:14
  • @sdfcfox I'm not sure I claimed that inserting the Contact first generates the Account. The fields provided in the foreign key reference (in this case Account) are used for finding the object and linking it to the object with a reference (in this case Contact). Those fields have to be either external IDs or indexed. Although one can check where objects point to, and unlike Java, there is no direct control over the heap - it's abstracted away from the user. I don't believe you can determine the exact point in time when the linking occurs, but I'd love to be corrected.
    – ipavlic
    Commented Sep 2, 2013 at 8:23
  • The last paragraph is confusing, then. "... it will automatically insert the related record ..." This was more a point of clarification. Also, Java and Apex Code have the same basic notion of heap, just one gives you control over heap size, one does not.
    – sfdcfox
    Commented Sep 2, 2013 at 12:21
  • You are right, that paragraph is not true and I was wrong. I've edited and corrected my mistake now. Yes, Apex and Java are very similar (it almost seems as if Salesforce translates Apex to Java in the background). With Java, one can also inspect the heap, choose garbage collection strategy, suggest garbage collection and use phantom, soft, weak or strong references - these all provide a way to control the heap (admittedly, indirectly).
    – ipavlic
    Commented Sep 2, 2013 at 20:14

You must log in to answer this question.

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