Long-note persistence¶
clsCustomerNote and clsContactNote are near-identical wrappers that store a customer's or contact's long-form note in COMPANY_NOTE or PERSON_NOTE, keyed by the owner's ID rather than embedded in the root COMPANY/PERSON row. Both classes are merged into this single operation page because they share the same retrieve/fill/save/delete pattern and differ only in their owning table and key column.
| Field | Value |
|---|---|
| Operation ID | OP-CC-08 |
| Trigger | Caller sets clsCustomer.LongNoteText or clsContact.LongNoteText, or reads it after a retrieve; persistence happens when the parent's Save() cascades to the note child in OnSaveComplete |
| Inputs | NoteText (up to 4000 characters), owning CustomerID or ContactID |
| Outputs | Persisted or deleted COMPANY_NOTE / PERSON_NOTE row |
| Primary components | clsCustomerNote.GetNote, clsCustomerNote.AfterRetrieve, clsContactNote.GetNote, clsContactNote.AfterRetrieve, clsCustomer.OnSave, clsContact.OnSave |
| Entry point | Business\SAIF.Business.CustomerContact\Customer\clsCustomerNote.vb, Business\SAIF.Business.CustomerContact\Contact\clsContactNote.vb |
Steps¶
- Expose the note through the parent.
clsCustomer.LongNoteTextproxiesCustomerNote.NoteText;clsContact.LongNoteTextproxiesContactNote.NoteText. TheCustomerNote/ContactNoteproperty lazily callsclsCustomerNote.GetNote(dpi, customerID)/clsContactNote.GetNote(dpi, contactID)on first access. - Retrieve the note row.
GetNoteruns the BOF retrieve pipeline keyed by the owner ID (customer: SQL-040 against COMPANY_NOTE; contact: SQL-033 against PERSON_NOTE). - Synthesize a note object when none exists.
AfterRetrievefills every returned row and callsMarkOld(); if the resultingNoteTextis blank (no row was found, or the row's text is empty), it callsCreate()andMarkClean()so callers always receive a usable, non-dirty note object even when noCOMPANY_NOTE/PERSON_NOTErow exists. - Delete-on-blank at parent save time (BR-009). In the parent's
OnSave(), if the noteIs Not IsNewandNoteText.Trim.Length = 0, the parent callsCustomerNote.Delete()/ContactNote.Delete()before the save cascade runs, so an existing note that has been cleared out is removed rather than persisted as an empty string. - Persist the note in the parent's save cascade.
OnSaveCompletecallsSaveChildObject(CustomerNote)/SaveChildObject(ContactNote)alongside the other child collections, which runs whichever of insert/update/delete applies: - Insert:
NOTE_TEXTand the owner key (customer: SQL-012; contact: SQL-006). - Update:
NOTE_TEXTby owner key (customer: SQL-070; contact: SQL-067). - Delete: by owner key (customer: SQL-086; contact: SQL-080).
- On failure (rows affected ≠ 1) for any of insert/update/delete: the corresponding
InsertError/UpdateError/DeleteErrorbroken rule is added and the note object is not marked clean/new.
Process flow¶
The following diagram visualizes the shared retrieve/blank-delete/save cycle used by both note types.
flowchart TD
Start([Parent retrieves CustomerNote/ContactNote]) --> Query[Query COMPANY_NOTE/PERSON_NOTE<br>by owner key]
Query --> Found{Row found with<br>non-blank NoteText?}
Found -->|Yes| MarkOld[Fill row; MarkOld]
Found -->|No| Synthesize[Create blank note object; MarkClean]
MarkOld --> Ready([Note object ready for LongNoteText access])
Synthesize --> Ready
Ready --> ParentSave([Parent Save runs])
ParentSave --> BlankCheck{Note not new<br>and NoteText blank?}
BlankCheck -->|Yes| DeleteNote[Delete note row]
BlankCheck -->|No| SaveNote[Insert or update note row]
DeleteNote --> Done([Save cascade continues])
SaveNote --> Done
Failure and edge-case behavior¶
- A blank note is deleted rather than persisted as empty text, so a customer/contact that never had a note (or whose note was cleared) always retrieves a fresh, clean note object rather than a stored blank row (BR-009).
- The blank-delete check only applies when the note
Is Not IsNew; a brand-new note that is created and left blank is simply never inserted, sinceOnSaveComplete'sSaveChildObjectcall has nothing dirty to persist.* - A contention failure (rows affected ≠ 1) on note insert/update/delete surfaces as a broken rule on the note object, not on the parent customer/contact, so callers must check both objects' broken-rule collections after
Save().*
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Related documentation¶
Sources¶
Business\SAIF.Business.CustomerContact\Customer\clsCustomerNote.vbBusiness\SAIF.Business.CustomerContact\Contact\clsContactNote.vbBusiness\SAIF.Business.CustomerContact\Customer\clsCustomer.vbBusiness\SAIF.Business.CustomerContact\Contact\clsContact.vb