---
title: Persist a correspondence or endorsement
summary: Insert or update a correspondence row through the BOF save lifecycle.
status: draft
owner: Technical Writer
last_reviewed: 2026-07-31
library: SAIF.Business.Policy.Correspondence
reference_type: package
operation_id: OP-004
trigger: Caller saves a `clsCorrespondence`, `clsEndorsement`, or their collection wrappers.
---

# Persist a correspondence or endorsement

Insert or update a correspondence row through the BOF save lifecycle.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-004 |
| **Trigger** | Caller saves a `clsCorrespondence`, `clsEndorsement`, or their collection wrappers. |
| **Inputs** | A dirty correspondence object plus any edit-session state held by the framework. |
| **Outputs** | An inserted or updated `ENDORSEMENT` row or a recorded error. |
| **Primary components** | `clsCorrespondence.BeforeInsert`, `clsCorrespondence.AfterInsert`, `clsCorrespondence.BeforeUpdate`, `clsCorrespondence.AfterUpdate` |
| **Entry point** | `Business\SAIF.Business.Policy.Correspondence\clsCorrespondence.vb` |

## Steps

1. Collection-based saves commit the active edit scope first by calling `ApplyEdit()` before delegating to the framework save pipeline ([BR-011](../business-rules.md#br-011-collection-save-applies-edits-before-framework-persistence)).
2. On insert, `BeforeInsert` creates a data request for `InsertSQL` and binds all correspondence columns ([SQL-002](../sql/SQL-002-saif-business-policy-correspondence.md), [ENDORSEMENT](../database-tables.md#endorsement)).
3. `AfterInsert` inspects the returned row count and records `InsertError` instead of marking the object old when the insert did not affect exactly one row ([BR-012](../business-rules.md#br-012-insert-and-update-must-affect-exactly-one-row)).
4. On update, `BeforeUpdate` binds `:LastUpdateDate`, restamps `UpdateUser` and `UpdateDate`, then binds the full column set for [SQL-016](../sql/SQL-016-saif-business-policy-correspondence.md) ([BR-013](../business-rules.md#br-013-updates-enforce-optimistic-concurrency-by-update-date)).
5. `AfterUpdate` uses the same one-row success rule as insert and records a DB-contention message on failure ([BR-012](../business-rules.md#br-012-insert-and-update-must-affect-exactly-one-row)).
6. Delete is not part of this operation because the criteria object throws `InvalidSQLProperty` for delete and create-SQL access ([BR-014](../business-rules.md#br-014-correspondence-does-not-expose-create-sql-or-delete-sql-criteria)).

## Process flow

The following diagram summarizes the control flow for this operation.

```mermaid
flowchart TD
    Start([Save request]) --> Edit[ApplyEdit] --> Mode{Insert or update?} -->|Insert| Insert[Run SQL-002] --> Check[RowsAffected = 1?] --> Return([Mark old or add error])
    Mode -->|Update| Update[Run SQL-016] --> Check
```

## Failure and edge-case behavior

- Validation and framework state errors surface through the BOF error collection unless the called dependency throws directly.
- Database-dependent operations rely on the caller-supplied data portal context and Oracle connectivity.
- Imaging reconciliation and stored-procedure wrappers defer cross-system behavior to their external collaborators.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

## Sources
- ``Business\SAIF.Business.Policy.Correspondence\clsCorrespondence.vb``
