---
title: Merge or upsert dictionary entries
summary: Merge, upsert, or safely read dictionary entries.
status: draft
owner: saif-docgen
last_reviewed: 2026-09-15
library: SAIF.Framework.Common
reference_type: package
operation_id: OP-034
trigger: Caller combines configuration/lookup dictionaries or reads with a fallback
---

# Merge or upsert dictionary entries

Merge, upsert, or safely read dictionary entries, triggered when caller combines configuration/lookup dictionaries or reads with a fallback.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-034 |
| **Trigger** | Caller combines configuration/lookup dictionaries or reads with a fallback |
| **Inputs** | Target dictionary, plus source dictionary / key / value / default |
| **Outputs** | `void` / `TValue` |
| **Primary components** | ``DictionaryExtensions.Merge<TValue>`, `TryGetValue<TKey,TValue>`, `UpdateOrAdd<TKey,TValue>`` |
| **Entry point** | `Common/SAIF.Common/Extensions/DictionaryExtensions.cs` |

## Steps

1. `Merge` iterates the source dictionary's pairs.
2. When `replaceExisting` is `false` and the target already contains the key, skip that pair; otherwise assign `instance[pair.Key] = pair.Value` (add-or-overwrite). The default is `replaceExisting = true`. ([BR-082](../business-rules.md#br-082-merging-dictionaries-overwrites-existing-keys-by-default))
3. `TryGetValue` guards the dictionary with `Enforce.ArgumentNotNull`, then returns the stored value if the key exists or the caller's `defaultValue` if not — it never throws `KeyNotFoundException`. ([BR-039](../business-rules.md#br-039-a-guarded-argument-must-not-be-null), [BR-083](../business-rules.md#br-083-a-dictionary-read-with-a-supplied-default-never-throws-on-a-missing-key))
4. `UpdateOrAdd` guards the dictionary with `Enforce.ArgumentNotNull`, then overwrites an existing key or adds a new one, and returns the value for chaining. ([BR-039](../business-rules.md#br-039-a-guarded-argument-must-not-be-null), [BR-084](../business-rules.md#br-084-an-upsert-overwrites-an-existing-key-or-adds-a-new-one-and-always-returns-the-supplied-value))

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start(["Caller merges, reads, or<br>upserts a dictionary"]) --> S1["Merge: iterate source<br>dictionary's pairs"]
	S1 --> S2{"replaceExisting is false<br>and key already exists?"}
	S2 -->|Yes| Skip["Skip this pair"]
	S2 -->|No| Assign["Assign instance[key] = value<br>(add or overwrite)"]
	Skip --> S3
	Assign --> S3["TryGetValue: guard dictionary,<br>return stored value or default"]
	S3 --> S4["UpdateOrAdd: guard dictionary,<br>overwrite or add, return value"]
	S4 --> End(["Result returned to caller"])
```

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `Common/SAIF.Common/Extensions/DictionaryExtensions.cs`
