Unit of Work Pattern
Intent
Problem Context
Core Implementation
1. Basic Unit of Work Pattern
// Unit of Work interface
public interface IUnitOfWork {
void registerNew(SObject record);
void registerNew(List<SObject> records);
void registerNew(SObject record, Schema.SObjectField relatedToField, SObject relatedTo);
void registerDirty(SObject record);
void registerDirty(List<SObject> records);
void registerDeleted(SObject record);
void registerDeleted(List<SObject> records);
void commitWork();
}
// Application configuration
public class Application {
// Define DML order for related objects
public static final fflib_Application.UnitOfWorkFactory UnitOfWork =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType, // Parents first
Contact.SObjectType, // Then children
Case.SObjectType,
CaseComment.SObjectType, // Grandchildren last
Task.SObjectType,
Event.SObjectType
}
);
public static IUnitOfWork newUnitOfWork() {
return UnitOfWork.newInstance();
}
}2. Understanding Transaction Boundaries
The Mental Model
Service Layer Pattern
3. Custom Work with IDoWork
When to Use Custom Work
Real-World Pattern: Post-Conversion Actions
4. Email Work Pattern
The Challenge with Transactional Emails
Solution: Email Work Registration
Understanding Execution Order
5. Testing with Mocked Unit of Work
Why Mock the Unit of Work?
The Mocking Pattern
Testing Custom Work
Implementation Patterns
1. Nested Unit of Work
2. Conditional Registration
Benefits
Trade-offs
Best Practices
1. Define Clear Object Order
2. Single Unit of Work Per Transaction
3. Pass Unit of Work to Methods
Anti-Patterns to Avoid
1. Premature Commits
2. Mixing Direct DML
Real-World Usage
Last updated
Was this helpful?