---
title: Log an application info event
summary: Persists a single application info/audit event to App_Info with a 30-day purge date 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-05
trigger: Caller invokes clsAppInfo.CreateNewAppInfo with either an AuditInfoStruct or discrete field values
---

# Log an application info event

Callers record an application info/audit event by calling one of the two `CreateNewAppInfo` factory overloads on `clsAppInfo` — one that accepts a framework `AuditInfoStruct` and one that accepts discrete field values. Both overloads populate the same set of fields on a new `clsAppInfo` instance, immediately call `Save()`, and rely on `BeforeInsert` to stamp a retention purge date independent of the caller's input.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-LV-05 |
| **Trigger** | Caller calls `clsAppInfo.CreateNewAppInfo(inDPI, inAuditStruct)` or `clsAppInfo.CreateNewAppInfo(inDPI, inAppName, inEnvironment, inAuditDate, inDataText, inMachineName, inPageName, inMessageText, inUserName)` |
| **Inputs** | `IDataPortalInfo`; either a `SAIF.Framework.Logging.AuditInfoStruct` or the eight discrete fields (`AppName`, `Environment`, `CreateDate`/`AuditDate`, `DataText`, `MachineName`, `PageName`, `MessageText`, `UserName`) |
| **Outputs** | Saved `clsAppInfo` instance with `AppInfoSeqNum` populated and `Purge_Date` set 30 days ahead; an `InsertError` business-object message if the insert did not affect exactly one row |
| **Primary components** | `clsAppInfo.CreateNewAppInfo` (both overloads), `clsAppInfo.BeforeInsert`, `clsAppInfo.AfterInsert` |
| **Entry point** | `Application\SAIF.Application.LogView\clsAppInfo.vb` |

## Steps

1. **Allocate a new object.** Both `CreateNewAppInfo` overloads build a `clsAppInfo.Criteria` from the supplied `IDataPortalInfo` and call `inDPI.DataAccessLayer.CreateObject(Crit)`, running the BOF `Create()` lifecycle method, which seeds fields to empty strings, `CreateDate` to `Now`, and `PurgeDate` to `Now` before the factory overwrites them.
2. **Populate fields from the caller's input.**
   - Struct overload: copies `ApplicationName`, `Environment`, `AuditDate` (into `CreateDate`), `DataText`, `MachineName`, `PageName`, `MessageText`, and `UserName` from the `AuditInfoStruct`.
   - Discrete-parameter overload: copies the eight caller-supplied arguments directly onto the same set of properties.
3. **Save the object.** Both overloads call `temp.Save()` immediately after populating fields, routing to the insert path for the new object.
4. **Build the insert request (`BeforeInsert`).** A `NonQuery` data request is configured with `MyCriteria.InsertSQL` ([SQL-004](../sql/SQL-004-saif-application-logview.md), [App_Info](../database-tables.md#app_info)) and bound parameters `@App_Name`, `@Create_Date` (or a `DbType.DateTime` null placeholder when `CreateDate` is `Date.MinValue`), `@Environment`, `@Machine_Name`, `@Page_Name`, `@Data_Text`, `@Purge_Date`, `@User_Name`, and `@Message_Text`.
   - `@Purge_Date` is always bound from `Now.AddDays(30)` computed at insert time, independent of any `PurgeDate` value the caller may have set on the object ([BR-007](../business-rules.md#br-007-audit-rows-receive-a-30-day-purge-date)).
   - A second scalar data request is queued with `SQLStatement = "Select @@IDENTITY"` ([SQL-002](../sql/SQL-002-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)).
   - Otherwise: read the `@@IDENTITY` scalar result, cast it to `Integer`, assign it to `AppInfoSeqNum`, and call `MarkOld()`.
6. **Return the saved object.** Both factory overloads return the same `temp` reference, now populated with `AppInfoSeqNum` on success.

## Process flow

The following diagram visualizes the two-overload create-and-save flow, including the fixed 30-day purge-date stamp.

```mermaid
flowchart TD
	Start([Caller calls CreateNewAppInfo]) --> Which{Struct or discrete<br>parameter overload?}
	Which -->|Struct| MapStruct[Map AuditInfoStruct fields<br>to clsAppInfo properties]
	Which -->|Discrete| MapDiscrete[Map discrete arguments<br>to clsAppInfo properties]
	MapStruct --> Save[Call Save]
	MapDiscrete --> Save
	Save --> Insert[BeforeInsert: build InsertSQL,<br>stamp Purge_Date = Now + 30 days]
	Insert --> Exec[Execute insert and<br>identity scalar request]
	Exec --> Rows{RowsAffected = 1?}
	Rows -->|No| Err([AddErrorMessage InsertError])
	Rows -->|Yes| Identity[Read @@IDENTITY,<br>set AppInfoSeqNum, MarkOld]
	Identity --> Done([Saved clsAppInfo returned])
```

## Failure and edge-case behavior

- The 30-day purge date is computed fresh in `BeforeInsert` from `Now.AddDays(30)` every time, so any `PurgeDate` value the caller set beforehand (including through the object's public setter) has no effect on the persisted row ([BR-007](../business-rules.md#br-007-audit-rows-receive-a-30-day-purge-date)).
- If `CreateDate` is left at `Date.MinValue`, `BeforeInsert` binds `@Create_Date` as an explicit `DbType.DateTime` null rather than a value.
- A `RowsAffected` value other than `1` is treated uniformly as an insert failure; `AppInfoSeqNum` remains unset and the object is not marked old.
- `clsAppInfo.AddBusinessRules()` 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\clsAppInfo.vb`
