Skip to main content

SF-0270 · Concept · Easy

How to access sObjects fields?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Apex offers two ways to read and write fields on an SObject record:

  1. Dot notation on the strongly-typed SObject (a.Name, a.Industry).
  2. Generic get/put on a base SObject reference (r.get('Name'), r.put('Industry', 'Tech')).

The first is the everyday way. The second is how dynamic Apex works.

1. Dot notation — the everyday case

When you have a typed SObject variable, you reference fields the same way as any Apex object property.

Account a = new Account(Name = 'Acme', Industry = 'Tech');
System.debug(a.Name);       // 'Acme'
a.Industry = 'Finance';     // re-assign
a.AnnualRevenue = 1000000;  // typed: must be Decimal

Dot notation requires the field to be loaded:

  • Fields populated in code (e.g., constructor argument).
  • Fields included in the SELECT clause of a SOQL query.
Account a = [SELECT Id, Name FROM Account LIMIT 1];
System.debug(a.Name);       // OK
System.debug(a.Industry);   // System.SObjectException: Industry not selected

This is one of the most common runtime errors in Apex — you forgot to include the field in your SELECT.

2. Dot notation across relationships

Relationship fields are traversed with . as well, but the field syntax differs:

  • Parent (lookup or master-detail) — use the relationship name:

    Contact c = [SELECT Id, Account.Name, Account.Industry FROM Contact LIMIT 1];
    System.debug(c.Account.Name);     // 'Acme'
    System.debug(c.Account.Industry); // 'Tech'
  • Child (one-to-many) — use a subquery; access the inner list via the relationship name:

    Account a = [SELECT Id, Name, (SELECT Id, LastName FROM Contacts) FROM Account LIMIT 1];
    for (Contact c : a.Contacts) {
        System.debug(c.LastName);
    }
  • Custom lookups use the relationship name minus __c plus __r:

    Order__c o = [SELECT Id, Customer__r.Name FROM Order__c LIMIT 1];
    System.debug(o.Customer__r.Name);

3. Generic get and put — for dynamic code

When you don’t know the SObject type at compile time, you use the base SObject interface and its get(String) and put(String, Object) methods.

SObject record = Schema.getGlobalDescribe().get('Account').newSObject();
record.put('Name', 'Acme');
record.put('Industry', 'Tech');
insert record;

String name = (String) record.get('Name');

A few things to call out:

  • get returns Object — you cast to the actual type.
  • put accepts an Object. Mismatched types throw IllegalArgumentException at runtime.
  • This is how packaged code, generic utilities, and metadata-driven controllers manipulate fields without hardcoding object names.

4. Setting fields when constructing

The sObject constructor accepts named parameters — the cleanest insert syntax:

Account a = new Account(
    Name = 'Acme',
    Industry = 'Tech',
    AnnualRevenue = 1000000
);
insert a;

Equivalent to:

Account a = new Account();
a.Name = 'Acme';
a.Industry = 'Tech';
a.AnnualRevenue = 1000000;
insert a;

The constructor form is preferred — it scans cleanly and produces fewer lines.

5. Reading fields from a Map<Id, SObject>

Common pattern: SOQL into a Map and look up a parent record by Id.

Map<Id, Account> byId = new Map<Id, Account>(
    [SELECT Id, Name, Industry FROM Account WHERE Id IN :accountIds]
);

for (Contact c : contacts) {
    Account a = byId.get(c.AccountId);
    if (a != null) {
        System.debug(c.LastName + ' works at ' + a.Name);
    }
}

The Map<Id, SObject> constructor that takes a query result is a daily-use idiom.

6. Polymorphic relationships (Task.WhoId, Task.WhatId)

Fields like Task.WhoId can point to multiple object types (Contact or Lead). Apex represents these with polymorphic dot syntax:

Task t = [SELECT Id, Who.Name, Who.Type FROM Task LIMIT 1];
System.debug(t.Who.Name);     // works regardless of whether Who is a Contact or Lead
System.debug(t.Who.Type);     // 'Contact' or 'Lead'

TYPEOF in SOQL is the formal way to handle this for typed access.

What interviewers are really looking for

The basic answer is “dot notation.” The senior-level answer covers: (1) the field must be SELECTed in the SOQL or you get a runtime SObjectException, (2) parent traversal uses the relationship name (Account.Name, Customer__r.Name), (3) child access uses subqueries and the relationship list, (4) get/put is how dynamic Apex reaches fields when the type isn’t known at compile time. Mention TYPEOF for polymorphic relationships and you’ve covered the corner cases.

Verified against: Apex Developer Guide — SObject Fields, SOQL Relationship Queries. Last reviewed 2026-05-17.