---
title: Menu categorization
summary: Maintains the lookup table of category codes used to classify menu items for grouping and display.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Menu
reference_type: package
operation_id: OP-MNU-02
trigger: Caller requests a category code by key, all categories, or saves a new/changed category
---

# Menu categorization

Menu categorization maintains `MENU_CATEGORY_CODE`, the simple two-column lookup table (`Code`, `Description`) that `clsMenuItem.MenuCategoryCode` references to group menu items for display. `clsMenuCategoryCode` follows the standard BOF CRUD lifecycle with no child objects and no computed fields.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MNU-02 |
| **Trigger** | Caller requests `clsMenuCategoryCode`/`clsMenuCategoryCodeCollection` by key or in full, or calls `Save()` after `Create()`/retrieve |
| **Inputs** | `Code` (key lookup); `Code`, `Description` (insert/update) |
| **Outputs** | Populated `clsMenuCategoryCode`/`clsMenuCategoryCodeCollection`; on save, a persisted row or an error message on DML contention |
| **Primary components** | `clsMenuCategoryCode`, `clsMenuCategoryCodeCollection` |
| **Entry point** | `Business\SAIF.Business.Menu\clsMenuCategoryCode.vb` |

## Steps

1. **Retrieve a single category code.** `clsMenuCategoryCode.GetMenuCategoryCode` creates a `Criteria` with the requested `Code` and invokes the data portal; `BeforeRetrieve` binds `:Code` and executes `RetrieveSQL` ([SQL-017](../sql/SQL-017-saif-business-menu.md), [MENU_CATEGORY_CODE](../database-tables.md#menu-category-code)). `AfterRetrieve` fills the object and marks it old.
2. **Retrieve the full collection.** `clsMenuCategoryCodeCollection.GetMenuCategoryCodes` executes the unfiltered `RetrieveSQL` ([SQL-018](../sql/SQL-018-saif-business-menu.md), [MENU_CATEGORY_CODE](../database-tables.md#menu-category-code)) and loads one `clsMenuCategoryCode` per row.
3. **Create a new category code.** `clsMenuCategoryCode.NewMenuCategoryCode` calls `Create()`, which simply sets `m_Code = MyCriteria.Code` — no sequence generation is involved because `Code` is a caller-supplied natural key rather than a generated surrogate key.*
4. **Save (insert) the code.** `BeforeInsert` binds `Code` (max length 5) and `Description` (max length 100) and executes `InsertSQL` ([SQL-006](../sql/SQL-006-saif-business-menu.md), [MENU_CATEGORY_CODE](../database-tables.md#menu-category-code)).
   - On success (`RowsAffected = 1`): `AfterInsert` calls `MarkOld()`.
   - On failure: `AddErrorMessage("InsertError", "Insert Failed")` ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
5. **Update the code's description.** `BeforeUpdate` binds `Description` and the key `Code`, then executes `UpdateSQL` ([SQL-032](../sql/SQL-032-saif-business-menu.md), [MENU_CATEGORY_CODE](../database-tables.md#menu-category-code)). `AfterUpdate` applies the row-count check, calling `MarkOld()` on success or adding `UpdateError` with `BOC.Messages.DBContentionError` otherwise ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
6. **Delete the code.** `BeforeDelete` binds `Code` and executes `DeleteSQL` ([SQL-039](../sql/SQL-039-saif-business-menu.md), [MENU_CATEGORY_CODE](../database-tables.md#menu-category-code)). `AfterDelete` calls `MarkNew()` on a rows-affected value of `1`, or adds a `DeleteError` otherwise ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
7. **Consume the classification.** `clsMenuItem.MenuCategory` and the [menu authorization data lookup](menu-authorization-data-lookup.md) UNION queries both join to `MENU_CATEGORY_CODE` on `Code` to resolve a human-readable category description for display; this library does not enforce that every `clsMenuItem.MenuCategoryCode` value has a matching row in `MENU_CATEGORY_CODE` — no foreign-key validation is performed in code.*

## Process flow

The following diagram visualizes the retrieve/save control flow for category codes.

```mermaid
flowchart TD
	Start([Caller requests category code<br>by key, all, or new]) --> Which{Operation?}
	Which -->|Retrieve by key| RetKey[Execute RetrieveSQL<br>with Code parameter]
	RetKey --> Fill[Fill object from reader;<br>MarkOld]
	Which -->|Retrieve all| RetAll[Execute unfiltered RetrieveSQL]
	RetAll --> FillEach[Load one object per row]
	Which -->|Create new| Assign[Set Code from criteria<br>no sequence lookup]
	Assign --> SaveCall{Save called?}
	SaveCall -->|Yes| Insert[Execute InsertSQL]
	Insert --> Rows{RowsAffected = 1?}
	Rows -->|Yes| Ok([MarkOld])
	Rows -->|No| Err([AddErrorMessage: InsertError])
```

## Failure and edge-case behavior

- Every insert, update, and delete enforces a strict rows-affected-equals-1 check; any other value raises `InsertError`, `UpdateError`, or `DeleteError` and the object is not marked clean ([BR-MNU-02](../business-rules.md#br-mnu-02-dml-row-count-enforcement)).
- `Code` is a caller-supplied natural key (no sequence), so two concurrent callers creating the same `Code` will conflict at the database's primary-key constraint rather than through this library's own logic.*
- No validation confirms a `clsMenuItem.MenuCategoryCode` value has a matching `MENU_CATEGORY_CODE.CODE` row before an item is saved; an orphaned category reference would surface only as a missing join result at query time, not as a save-time error.*

## 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
- `Business\SAIF.Business.Menu\clsMenuCategoryCode.vb`
- `Business\SAIF.Business.Menu\clsMenuCategoryCodeCollection.vb`
