---
title: Log an application error
summary: Persists a single application error event to App_Error and returns the object with its generated sequence number.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Application.LogView
reference_type: package
operation_id: OP-LV-01
trigger: Caller invokes clsAppError.CreateNewAppError with either an ErrorInfoStruct or discrete field values
---

# Log an application error

Callers record an application error by calling one of the two `CreateNewAppError` factory overloads on `clsAppError` — one that accepts a framework `ErrorInfoStruct` and one that accepts discrete field values. Both overloads populate the same set of fields on a new `clsAppError` instance and immediately call `Save()`, so both converge on the identical insert-and-identity-retrieval lifecycle.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-LV-01 |
| **Trigger** | Caller calls `clsAppError.CreateNewAppError(inDPI, inErrorStruct)` or `clsAppError.CreateNewAppError(inDPI, inAppName, inEnvironment, inErrorDate, inErrorInfo, inErrorSource, inMachineName, inPageName, inStateInfo, inUserName)` |
| **Inputs** | `IDataPortalInfo`; either a `SAIF.Framework.Logging.ErrorInfoStruct` or the nine discrete fields (`AppName`, `Environment`, `ErrorDate`, `ErrorInfo`, `ErrorSource`, `MachineName`, `PageName`, `StateInfo`, `UserName`) |
| **Outputs** | Saved `clsAppError` instance with `AppErrorSeqNum` populated; an `InsertError` business-object message if the insert did not affect exactly one row |
| **Primary components** | `clsAppError.CreateNewAppError` (both overloads), `clsAppError.BeforeInsert`, `clsAppError.AfterInsert` |
| **Entry point** | `Application\SAIF.Application.LogView\clsAppError.vb` |

## Steps

1. **Allocate a new object.** Both `CreateNewAppError` overloads build a `clsAppError.Criteria` from the supplied `IDataPortalInfo` and call `inDPI.DataAccessLayer.CreateObject(Crit)`, which runs the BOF `Create()` lifecycle method. `Create()` seeds all fields to empty strings and sets `ErrorDate` to `Now` before the factory overwrites them.
2. **Populate fields from the caller's input.**
   - Struct overload: copies `ApplicationName`, `Environment`, `ErrorDate`, `ExceptionInfo`, `ExceptionSource`, `MachineName`, `PageName`, `StateInfo`, and `Username` from the `ErrorInfoStruct` onto the corresponding `clsAppError` properties.
   - Discrete-parameter overload: copies the nine caller-supplied arguments directly onto the same set of properties.
   - Each property setter calls `MarkDirty()` when the incoming value differs from the current value, which is what makes the object savable.
3. **Save the object.** Both overloads call `temp.Save()` immediately after populating fields, entering the BOF save lifecycle for a new (dirty, not-yet-persisted) object, which routes to `BeforeInsert`/`AfterInsert` rather than update.
4. **Build the insert request (`BeforeInsert`).** A `NonQuery` data request is configured with `MyCriteria.InsertSQL` ([SQL-003](../sql/SQL-003-saif-application-logview.md), [App_Error](../database-tables.md#app_error)) and bound parameters `@App_Name`, `@Error_Date` (or a `DbType.DateTime` null placeholder when `ErrorDate` is `Date.MinValue`), `@Environment`, `@Machine_Name`, `@Page_Name`, `@Error_Source`, `@State_Info`, `@Error_Info`, and `@User_Name`.
   - A second scalar data request is queued in the same call with `SQLStatement = "Select @@IDENTITY"` ([SQL-001](../sql/SQL-001-saif-application-logview.md)) to retrieve the generated sequence number in the same round trip.
5. **Evaluate the insert result (`AfterInsert`).** The rows-affected value from the first data request is read.
   - If `RowsAffected <> 1`: add the `InsertError` business-object message ([BR-006](../business-rules.md#br-006-inserts-must-affect-exactly-one-row)) and leave `AppErrorSeqNum` unset — the object is not marked old, so it still reports as new/dirty.
   - Otherwise: read the `@@IDENTITY` scalar result from the second data request, cast it to `Integer`, assign it to `m_AppErrorSeqNum`, and call `MarkOld()` to mark the object as persisted and clean.
6. **Return the saved object.** Both factory overloads return the same `temp` reference used throughout, now populated with `AppErrorSeqNum` on success.

## Process flow

The following diagram visualizes the two-overload create-and-save flow.

```mermaid
flowchart TD
	Start([Caller calls CreateNewAppError]) --> Which{Struct or discrete<br>parameter overload?}
	Which -->|Struct| MapStruct[Map ErrorInfoStruct fields<br>to clsAppError properties]
	Which -->|Discrete| MapDiscrete[Map discrete arguments<br>to clsAppError properties]
	MapStruct --> Save[Call Save]
	MapDiscrete --> Save
	Save --> Insert[BeforeInsert: build InsertSQL<br>and @@IDENTITY requests]
	Insert --> Exec[Execute insert and<br>identity scalar request]
	Exec --> Rows{RowsAffected = 1?}
	Rows -->|No| Err([AddErrorMessage InsertError;<br>AppErrorSeqNum unset])
	Rows -->|Yes| Identity[Read @@IDENTITY,<br>set AppErrorSeqNum, MarkOld]
	Identity --> Done([Saved clsAppError returned])
```

## Failure and edge-case behavior

- If `ErrorDate` is left at `Date.MinValue` (never assigned), `BeforeInsert` binds `@Error_Date` as an explicit `DbType.DateTime` null rather than a value, so the row is inserted with a null error date.
- A `RowsAffected` value other than `1` — including `0` or more than `1` — is treated uniformly as an insert failure; `AppErrorSeqNum` remains unset and the object is not marked old, so a subsequent `Save()` would attempt the insert again.
- `AfterInsert` does not validate `IsValid` before proceeding, and `AddBusinessRules()` on `clsAppError` registers no rules, so no field-level validation blocks the insert.*

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

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `Application\SAIF.Application.LogView\clsAppError.vb`
