Saturday, July 12, 2025

User Mode vs WITH SECURITY_ENFORCED in Apex


Feature / Aspect

User Mode

WITH SECURITY_ENFORCED

Purpose

Enforces user permissions (FLS & CRUD) automatically in SOQL and DML

Enforces FLS & CRUD in SOQL only

Scope

Works with SOQL, DML, Async Apex (Batch, Queueable, etc.)

Works only with SOQL

Syntax Example

Database.query(new Query("SELECT Name FROM Account").setUserMode(UserMode.CURRENT));

[SELECT Name FROM Account WITH SECURITY_ENFORCED];

Field-Level Security (FLS)

Respected automatically

Respected, but throws error if access is denied

Object-Level Security (CRUD)

Respected automatically

Respected, but throws error if access is denied

Partial Access Handling

Returns only accessible fields/objects

Fails completely if any field/object is restricted

Error Handling

No error thrown for restricted fields; they are silently excluded

Throws uncatchable exception if access is denied

Support for Relationship Fields

✅ Supported

❌ Not supported (e.g., Owner.Name fails)

Support in Dynamic SOQL

✅ Fully supported

❌ Not supported

Support in DML Operations

✅ Supported via Database.DMLOptions.setUserMode()

❌ Not supported

Async Apex Compatibility

✅ Works in Batch, Queueable, etc.

❌ Not supported

Ease of Use

Cleaner, safer, and more flexible

Requires careful handling and limited in scope

Salesforce Recommendation

✅ Recommended

❌ Not recommended anymore

Use Case Example

Secure insert: Database.insert(record, dmlOpts);

Secure query: [SELECT Name FROM Account WITH SECURITY_ENFORCED];

Limitations

Few limitations; more flexible

Many limitations (no dynamic SOQL, no DML, no async, no partial results)

Can Be Used Together?

❌ Cannot be combined with WITH SECURITY_ENFORCED

❌ Cannot be combined with UserMode

Understanding DescribeFieldResult in Apex with Real-Time Examples

In Salesforce Apex, the Schema.DescribeFieldResult class provides metadata about fields on standard and custom objects. This is especially useful when building dynamic applications that need to adapt to different field configurations or enforce field-level security.

To instantiate a DescribeFieldResult object, you can use the following syntax:

Schema.DescribeFieldResult dfr = Account.Description.getDescribe();

This retrieves metadata about the Description field on the Account object. Let’s explore some of the most useful methods available in DescribeFieldResult, with real-time examples for selected ones.

getPicklistValues()

Returns a list of active PicklistEntry objects for a picklist field.

Example:

Schema.DescribeFieldResult dfr = Account.Industry.getDescribe();

List<Schema.PicklistEntry> picklistValues = dfr.getPicklistValues();

for (Schema.PicklistEntry entry : picklistValues) {

    System.debug('Picklist Value: ' + entry.getLabel());

}

getSObjectType()

Returns the object type from which the field originates.

Example:

Schema.DescribeFieldResult dfr = Account.Name.getDescribe();

Schema.SObjectType objType = dfr.getSObjectType();

System.debug('Object Type: ' + objType.getDescribe().getName());

isAccessible()

Checks if the current user has visibility to the field.

Example:

Schema.DescribeFieldResult dfr = Contact.Email.getDescribe();

if (dfr.isAccessible()) {

    System.debug('User can access the Email field.');

} else {

    System.debug('User cannot access the Email field.');

}

isUpdateable()

Checks if the field can be edited by the current user.

Example:

Schema.DescribeFieldResult dfr = Opportunity.StageName.getDescribe();

if (dfr.isUpdateable()) {

    System.debug('User can update the StageName field.');

} else {

    System.debug('User cannot update the StageName field.');

}

Conclusion:

Using DescribeFieldResult methods allows developers to build smarter, more secure, and dynamic applications in Salesforce. Whether you're validating permissions, fetching picklist values, or inspecting field metadata, these tools are essential for robust Apex development.

Mastering OOP in Salesforce Apex: A Quick Guide

Salesforce Apex is a powerful, object-oriented programming language tailored for the Salesforce platform. Understanding the principles of Object-Oriented Programming (OOP) in Apex is essential for building scalable, maintainable, and reusable code.

What is OOP in Apex?

OOP is a programming paradigm based on the concept of "objects", which can contain data and code. Apex supports all four core OOP principles:

Encapsulation:

Encapsulation allows you to bundle data (variables) and methods that operate on the data into a single unit—called a class. It also helps protect data by restricting access using access modifiers like private, public, and protected.

public class LibraryBook {
    private String title;
    private Boolean isCheckedOut;

    public void checkOut() {
        isCheckedOut = true;
    }

    public Boolean getStatus() {
        return isCheckedOut;
    }
}

Abstraction:

Abstraction hides complex implementation details and exposes only the necessary parts of an object. In Apex, this is achieved using abstract classes and interfaces.The Shape class defines an abstract method area(), and Circle provides its specific implementation.

public abstract class Payment {
    public abstract void processPayment();
}

public class CreditCardPayment extends Payment {
    public override void processPayment() {
        System.debug('Processing credit card payment');
    }
}

Inheritance:

Inheritance enables a class (child) to inherit properties and methods from another class (parent). This promotes code reuse and logical hierarchy.

public class Vehicle {
    public void start() {
        System.debug('Vehicle started');
    }
}

public class Truck extends Vehicle {
    public void loadCargo() {
        System.debug('Cargo loaded');
    }
}

Polymorphism:

Polymorphism allows methods to behave differently based on the object that is calling them. Apex supports both compile-time (method overloading) and runtime (method overriding) polymorphism.

Polymorphism lets you use a single interface to represent different types.

public virtual class Notification {
    public virtual void send() {
        System.debug('Sending generic notification');
    }
}

public class EmailNotification extends Notification {
    public override void send() {
        System.debug('Sending email notification');
    }
}

public class PushNotification extends Notification {
    public override void send() {
        System.debug('Sending push notification');
    }
}

// Usage
Notification n1 = new EmailNotification();
Notification n2 = new PushNotification();
n1.send(); // Sending email notification
n2.send(); // Sending push notification

Explanation of compile-time polymorphism (method overloading) and runtime polymorphism (method overriding) in Apex, along with examples:

Compile-time polymorphism occurs when multiple methods in the same class have the same name but different parameter lists (type, number, or order). The method that gets called is determined at compile time.

Example:

public class Calculator {
    public Integer add(Integer a, Integer b) {
        return a + b;
    }

    public Decimal add(Decimal a, Decimal b) {
        return a + b;
    }

    public Integer add(Integer a, Integer b, Integer c) {
        return a + b + c;
    }
}

Calculator calc = new Calculator();
System.debug(calc.add(2, 3));           // Calls method with two Integers
System.debug(calc.add(2.5, 3.5));       // Calls method with two Decimals
System.debug(calc.add(1, 2, 3));        // Calls method with three Integers

Runtime polymorphism occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The method that gets executed is determined at runtime based on the object type.

Example:

public virtual class Animal {
    public virtual void makeSound() {
        System.debug('Animal makes sound');
    }
}

public class Dog extends Animal {
    public override void makeSound() {
        System.debug('Dog barks');
    }
}

public class Cat extends Animal {
    public override void makeSound() {
        System.debug('Cat meows');
    }
}

Animal a1 = new Dog();
Animal a2 = new Cat();
a1.makeSound(); // Outputs: Dog barks
a2.makeSound(); // Outputs: Cat meows


Why OOP Matters in Apex?

Using OOP in Apex helps developers:

  • Write cleaner and more modular code
  • Reduce redundancy
  • Improve code maintainability
  • Enhance collaboration in large projects

Sunday, July 6, 2025

Savepoint & Rollback in Apex

In Salesforce Apex, Savepoint and Rollback work like an “undo” feature for database changes during a transaction. They help prevent unwanted data from being saved if something goes wrong in your code execution.

What is a Savepoint?

A Savepoint marks a specific stage in your transaction. Everything done before the savepoint is considered safe. If an error occurs after the savepoint, you can roll back to that point.

Savepoint sp = Database.setSavepoint();

What is a Rollback?

Rollback undoes all database changes made after a savepoint. It does not affect records inserted, updated, or deleted before the savepoint.

Database.rollback(sp);


Example 1: Using Savepoint and Rollback

Account acc1 = new Account(Name='First Account');

insert acc1;


// Set savepoint

Savepoint sp = Database.setSavepoint();


Account acc2 = new Account(Name='Second Account');

insert acc2;


// Simulate an error

if (true) {

    Database.rollback(sp);

}

Result:

  • acc1 is saved.
  • acc2 is rolled back.
  • No exception is thrown.


Example 2: Without Savepoint and Rollback

Account acc1 = new Account(Name='First Account');

insert acc1;


Account acc2 = new Account(Name='Second Account');

insert acc2;


// Simulate an error

if (true) {

    throw new CustomException('Something went wrong!');

}

Result:

  • Entire transaction fails.
  • Neither acc1 nor acc2 is saved.
  • A custom exception is thrown.


Why This Matters

Without Savepoints, any error rolls back all changes in the transaction. Even valid data that was saved before the error is lost.
With Savepoints, you can protect the valid part of the transaction and only undo the part that failed.


Real-World Use Case

Suppose you are creating three related records in one transaction:

  • An Account
  • A Contact
  • An Opportunity

If the Opportunity creation fails, you can use a savepoint before inserting it and roll back just that part — keeping the Account and Contact saved.


When to Use Savepoint and Rollback

  • When you want to protect only part of a transaction.
  • When you expect possible failures in specific DML operations.
  • When you want more control over error handling and data safety.


Limitations of Savepoint and Rollback in Apex

1. Rolling Back Invalidates Later Savepoints

If you create multiple savepoints and roll back to an earlier one, any savepoints created after that become invalid. Using those invalidated savepoints will cause a runtime error.

Example:

Savepoint sp1 = Database.setSavepoint(); // First savepoint


Account acc1 = new Account(Name = 'First');

insert acc1;


Savepoint sp2 = Database.setSavepoint(); // Second savepoint


Account acc2 = new Account(Name = 'Second');

insert acc2;


// Roll back to first savepoint

Database.rollback(sp1);


// Now sp2 is invalid. Using it will cause a runtime error

Database.rollback(sp2); // This line will throw an error


2. Savepoints Do Not Work Across Trigger Invocations

Each time a trigger is executed, it runs in a separate context. If you try to use a savepoint created in one trigger execution inside another, it will not work — even if stored in a static variable.

Step-by-Step Example:

Apex Class:

public class SavepointHolder {

    public static Savepoint sp;

}

Trigger Code:

trigger AccountTrigger on Account (before insert) {

    if (Trigger.isBefore) {

        if (SavepointHolder.sp == null) {

            // First trigger execution: set savepoint

            SavepointHolder.sp = Database.setSavepoint();

            System.debug('Savepoint set in first trigger run.');

        } else {

            // Second trigger execution: try to use old savepoint

            Database.rollback(SavepointHolder.sp); // This will throw an error

            System.debug('Trying to use savepoint from earlier run.');

        }

    }

}

Result:

  • First trigger run: savepoint is set.
  • Second trigger run: trying to use the same savepoint causes a runtime error.


3. Savepoints Count Against DML Limits

Salesforce enforces a limit of 150 DML operations per transaction. Every time you create a savepoint, it counts as one DML operation.

Example:

for (Integer i = 0; i < 150; i++) {

    Savepoint sp = Database.setSavepoint(); // Each counts as DML

}

Result:

  • DML limit is reached just by setting savepoints.
  • No room left for actual insert, update, or delete operations.
  • Transaction fails if more DML is attempted.