apex-record-clone-patterns
SObject.clone(preserveId, isDeepClone, preserveReadonly, preserveAutonumber): shallow vs deep clone semantics, related-record replication, clone with parent repointing, autonumber preservation. NOT for data migration (use bulk-api-and-large-data-loads). NOT for record snapshots (use field-history-tracking).
Best use case
apex-record-clone-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
SObject.clone(preserveId, isDeepClone, preserveReadonly, preserveAutonumber): shallow vs deep clone semantics, related-record replication, clone with parent repointing, autonumber preservation. NOT for data migration (use bulk-api-and-large-data-loads). NOT for record snapshots (use field-history-tracking).
Teams using apex-record-clone-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/apex-record-clone-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How apex-record-clone-patterns Compares
| Feature / Agent | apex-record-clone-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
SObject.clone(preserveId, isDeepClone, preserveReadonly, preserveAutonumber): shallow vs deep clone semantics, related-record replication, clone with parent repointing, autonumber preservation. NOT for data migration (use bulk-api-and-large-data-loads). NOT for record snapshots (use field-history-tracking).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Apex Record Clone Patterns
Activate when duplicating an sObject record in Apex — one record with a new Id, a record with its children, or a snapshot with preserved audit fields. The `SObject.clone()` method has four boolean flags that control deep-vs-shallow, Id preservation, readonly-field behavior, and autonumber handling. Each has failure modes if misread.
## Before Starting
- **Define scope.** Just the record, or the record + children? Clone does NOT walk relationships by default.
- **Decide Id preservation.** Cloning for insert → `preserveId=false` (default). Cloning for in-memory work → `preserveId=true`.
- **Audit-field expectations.** `CreatedDate`, `LastModifiedDate`, etc. are readonly; `preserveReadonly=true` requires `CreateAuditFields` user permission.
## Core Concepts
### Method signature
```
public SObject clone(Boolean preserveId, Boolean isDeepClone, Boolean preserveReadonly, Boolean preserveAutonumber)
```
All four default to `false`. Typical invocations:
```
Account copy = acc.clone(); // shallow, no Id, no readonly, new autonumber
Account copy = acc.clone(false, false, false, true); // preserve autonumber
Account copy = acc.clone(true); // keep Id (for in-memory diffing)
```
### Flags in detail
| Flag | Meaning |
|---|---|
| `preserveId` | Clone has the same Id as original (rarely useful — can't `insert` a record with Id) |
| `isDeepClone` | Copies field values regardless of type (but NOT related records) |
| `preserveReadonly` | Copies `CreatedDate`, `CreatedById`, `LastModifiedDate`, `SystemModstamp`. Requires `CreateAuditFields` perm |
| `preserveAutonumber` | Clone carries the same autonumber value |
### "Deep clone" does NOT clone children
`isDeepClone=true` is a misnomer — it preserves formula/aggregate field values in the in-memory copy. It does NOT fetch and clone child records.
### Cloning children requires explicit query + reparent
```
Opportunity opp = [SELECT Id, Name, (SELECT Id, Product2Id, Quantity, UnitPrice FROM OpportunityLineItems) FROM Opportunity WHERE Id = :srcId];
Opportunity newOpp = opp.clone(false, false, false, false);
newOpp.Name = 'Copy of ' + opp.Name;
insert newOpp;
List<OpportunityLineItem> newLines = new List<OpportunityLineItem>();
for (OpportunityLineItem oli : opp.OpportunityLineItems) {
OpportunityLineItem copy = oli.clone();
copy.OpportunityId = newOpp.Id;
newLines.add(copy);
}
insert newLines;
```
### Readonly-field preservation
```
Account a = [SELECT Id, Name, CreatedDate FROM Account WHERE Id = :id];
Account copy = a.clone(false, false, true, false);
insert copy; // CreatedDate preserved — only if running user has CreateAuditFields permission
```
Perm gate: Setup → System Permissions → "Set Audit Fields upon Record Creation" must be enabled and permission assigned.
## Common Patterns
### Pattern: "Copy of" with new autonumber
```
Case c = [SELECT Id, Subject, Origin FROM Case WHERE Id = :id];
Case copy = c.clone(); // CaseNumber autonumber regenerated
copy.Subject = 'Copy of ' + c.Subject;
insert copy;
```
### Pattern: Deep copy of Opportunity with line items
(See "Cloning children" code above.)
### Pattern: Bulk clone 1→N
```
List<Account> src = [SELECT Id, Name FROM Account WHERE ...];
List<Account> copies = new List<Account>();
for (Account a : src) {
for (Integer i = 0; i < 5; i++) {
Account c = a.clone();
c.Name = a.Name + ' v' + i;
copies.add(c);
}
}
insert copies;
```
### Pattern: Clone via `Database.insert` with duplicate-rule bypass
```
Database.DMLOptions dmo = new Database.DMLOptions();
dmo.DuplicateRuleHeader.AllowSave = true;
List<Database.SaveResult> srs = Database.insert(copies, dmo);
```
## Decision Guidance
| Scenario | Flags |
|---|---|
| Duplicate a record, new Id, new autonumber | `clone()` |
| Duplicate a record, preserve autonumber | `clone(false, false, false, true)` |
| In-memory copy for comparison (no insert) | `clone(true, false, false, false)` |
| Data migration preserving CreatedDate | `clone(false, false, true, false)` + user perm |
| Duplicate record + children | query children, clone, reparent, insert parent first |
## Recommended Workflow
1. Identify whether children need to travel. If yes, query the subselect in the source SOQL.
2. Clone the parent with the flags you need (usually `clone()` is sufficient).
3. Insert the parent first to obtain the new Id.
4. Clone each child, set the foreign key to the new parent Id, insert in bulk.
5. For audit-field preservation, verify the running user has `CreateAuditFields`.
6. Test with duplicate rules enabled AND disabled.
7. Document the clone's semantic relationship to the source (e.g., store a `Cloned_From__c` lookup for traceability).
## Review Checklist
- [ ] Child records explicitly queried + reparented (clone does NOT do this)
- [ ] Autonumber preservation decision intentional
- [ ] Audit-field preservation paired with `CreateAuditFields` permission
- [ ] Bulk clone keeps DML inside limits
- [ ] Clone traceability (e.g., source-record lookup) persisted
- [ ] Duplicate rule behavior considered
## Salesforce-Specific Gotchas
1. **`clone()` does NOT recursively clone children.** `isDeepClone=true` preserves formula values but doesn't fetch relationships.
2. **`preserveId=true` followed by `insert` throws — you cannot insert with an Id.** Only useful for in-memory diffing/asserting.
3. **`preserveReadonly=true` without `CreateAuditFields` silently ignores audit fields** — the new record gets `SYSTEM.now()` timestamps, not the originals.
4. **OpportunityLineItem clone requires a Price Book Entry that exists on the target Opportunity** — cloning across pricebooks needs repointing.
5. **Record Type Id is not cleared by clone** — ensure target record type is valid for the cloned picklist values.
## Output Artifacts
| Artifact | Description |
|---|---|
| Clone utility class | Reusable parent + children cloner |
| Traceability field | `Cloned_From__c` lookup to source |
| Permission doc | Note `CreateAuditFields` requirement for audit-preserving clones |
## Related Skills
- `apex/apex-record-relationships` — relationship traversal for deep copies
- `data/bulk-api-and-large-data-loads` — volume cloning via ETL
- `data/external-id-strategy` — matching source/target across orgsRelated Skills
record-access-troubleshooting
Diagnose why a user can or cannot see/edit a record: UserRecordAccess SOQL, Why Can a User Access This Record debug log, OWD, role hierarchy, sharing rules, manual/team/apex shares, implicit parent share. NOT for field-level security (use field-level-security-audit). NOT for designing sharing (use sharing-selection decision tree).
mfa-enforcement-patterns
Design MFA enforcement: auto-enablement, Salesforce Authenticator rollout, exceptions, service accounts, API-only users, SSO interop, and audit. Trigger keywords: MFA, multi-factor, two-factor, Salesforce Authenticator, MFA exception, MFA SSO, api-only MFA. Does NOT cover: end-user password policies, device-trust posture, or non-Salesforce IdP configuration.
encrypted-field-query-patterns
Design SOQL, filters, reporting, and indexes against Shield Platform Encryption fields. Trigger keywords: Shield Platform Encryption, encrypted field query, probabilistic vs deterministic encryption, encrypted SOQL filter, encrypted field index. Does NOT cover: Classic Encryption (deprecated), field-level security policy, or tenant secret key rotation.
apex-managed-sharing-patterns
Grant row-level access programmatically via __Share records when declarative sharing rules cannot express the policy. NOT for OWD, role hierarchy, or criteria-based sharing rule design.
omnistudio-testing-patterns
Use when testing or validating OmniStudio components — OmniScript preview, Integration Procedure step debugging, DataRaptor field-mapping validation, and end-to-end UTAM-based automation. NOT for Apex unit testing or standard Flow debugging.
omnistudio-error-handling-patterns
Use when designing fault behavior across Integration Procedures, DataRaptors, OmniScripts, and FlexCards — error routing, user-facing messaging, retry semantics, and idempotency. Triggers: 'omnistudio error', 'integration procedure fault', 'dataraptor error handling', 'omniscript retry', 'flexcard action failure'. NOT for general Apex exception design or Flow fault paths.
omnistudio-ci-cd-patterns
Use when designing or implementing CI/CD pipelines for OmniStudio components — DataPack export/import, versioning, environment promotion, and automated deployment. NOT for standard Salesforce metadata CI/CD or Apex-only pipelines.
omniscript-design-patterns
Use when designing or reviewing OmniScripts for guided experiences, step structure, branching, save/resume, and the boundary between OmniScript, Integration Procedures, DataRaptors, and custom LWCs. Triggers: 'omniscript design', 'too many steps in omniscript', 'save and resume omniscript', 'branching in omniscript', 'when should this be an integration procedure'. NOT for deep Integration Procedure or DataRaptor design when the guided interaction layer is not the main concern.
integration-procedure-cacheable-patterns
Use when designing Integration Procedures (IPs) with platform cache to cut latency and callout load. Covers cache key design, TTL selection, per-user vs org-wide partitions, invalidation on data changes, and safe fallback on cache miss/stale. Does NOT cover general IP authoring (see omnistudio-error-handling-patterns) or LWC client-side caching.
flexcard-design-patterns
Use when designing, building, or reviewing OmniStudio FlexCards — including data source selection, card states, actions, conditional visibility, flyout configuration, and child card iteration. Triggers: 'FlexCard', 'card template', 'flyout', 'card action', 'card state', 'data source', 'child card', 'conditional visibility'. NOT for OmniScript design, standalone LWC development, or Apex controller architecture outside the FlexCard context.
dataraptor-patterns
Use when designing or reviewing OmniStudio DataRaptors, especially Extract versus Turbo Extract versus Transform versus Load, field mapping strategy, performance tradeoffs, and when to move work into Integration Procedures or Apex. Triggers: 'DataRaptor Extract', 'Turbo Extract', 'DataRaptor Load', 'DataRaptor Transform', 'OmniStudio data mapping'. NOT for overall OmniScript journey design or Integration Procedure sequencing when the main question is not the DataRaptor shape itself.
wire-service-patterns
Use when designing or reviewing Lightning Web Components that use `@wire`, Lightning Data Service, UI API, or the GraphQL wire adapter, especially for reactive parameters, cache behavior, and refresh strategy. Triggers: 'wire service', 'refreshApex', 'reactive parameter', 'getRecord', 'wire vs imperative Apex'. NOT for component communication or generic lifecycle issues when data provisioning is not the main concern.