Skip to content

SAIF.Framework.Preferences architecture

SAIF.Framework.Preferences is a small, self-contained data-access library that persists per-user application/page preference blobs. It consists of exactly two classes — the Preference DTO and the PreferenceData data-access class — and reads/writes a single Oracle table, USER_PREFERENCE, via inline SQL rather than the framework's standard business-object pattern.

Responsibilities

  • Provide a data-access surface for reading a single preference blob (GetPreferences), reading all preferences for a user (GetPreferencesForUser), and upserting/deleting a preference (SavePreferences).
  • Represent one saved preference record as a simple DTO (Preference), carrying application name, page name, preference ID, and a deserialized key/value item dictionary.
  • Normalize and scope preference identity by application name, user ID (lower-cased), and optional page name.
  • Serialize/deserialize the stored preference payload as JSON (PREFERENCE_TEXT) using JavaScriptSerializer.

Component boundaries

  • Preference (SAIF.Framework.Preferences\Preference.cs): plain data-transfer object. Public fields PreferenceId, ApplicationName, Pagename, PreferenceItems; no behavior beyond a parameterless constructor.
  • PreferenceData (SAIF.Framework.Preferences\PreferenceData.cs): the sole data-access class. Public methods GetPreferences, GetPreferencesForUser, SavePreferences; private helpers InsertPref, UpdatePref, DeletePref, DoesPrefExist. Constructed with an injected IDataPortalInfo (DPI field) supplied by the caller.
  • External boundary — SAIF.Framework (built from SAIF.Framework.Core): supplies IDataPortalInfo, SqlHelper.ResultSetQuery, SqlHelper.ScalarQuery<T>, SqlHelper.NewParm, and clsResultSet.DataRow. This library has no <ProjectReference> to SAIF.Framework.Core; it references the compiled SAIF.Framework.dll via a HintPath binary reference.
  • Database boundary — USER_PREFERENCE (Oracle), the single table this library reads and writes, keyed via the USER_PREFERENCE_SEQ sequence.

Interaction model

  • Host applications construct PreferenceData by supplying an IDataPortalInfo instance; this library does not resolve its own connection/portal context.
  • GetPreferences builds a parameterized SELECT scoped by USER_ID/APP_NAME/optional PAGE_NAME (see SQL-002), executes it via SqlHelper.ResultSetQuery, and returns the raw PREFERENCE_TEXT string (or string.Empty if no row matches).
  • GetPreferencesForUser selects all rows for a USER_ID (see SQL-003), builds one Preference object per row, and deserializes non-empty PREFERENCE_TEXT JSON into PreferenceItems via JavaScriptSerializer.
  • SavePreferences is the single write entry point: it branches to DeletePref (see SQL-006) when preferenceText is empty/whitespace, otherwise checks DoesPrefExist (see SQL-007) and dispatches to UpdatePref (see SQL-005) or InsertPref (see SQL-001 and SQL-004) accordingly. All three internal operations execute via SqlHelper.ScalarQuery<int>.
  • There is no application/UI layer code in this library — it is a reusable component intended to be consumed by host applications.

Architecture diagram

The following diagram shows the high-level component interactions for this library.

flowchart TD
    Caller["Host application"] --> PD["PreferenceData"]
    PD --> DTO["Preference (DTO)"]
    PD --> DPI["IDataPortalInfo<br>(injected by caller)"]
    PD --> SqlHelper["SqlHelper.ResultSetQuery /<br>SqlHelper.ScalarQuery&lt;T&gt;<br>(SAIF.Framework)"]
    SqlHelper --> DB[("USER_PREFERENCE<br>(Oracle)")]

Sequence diagram

The following diagram shows the primary save (upsert/delete) request sequence.

sequenceDiagram
    participant Caller as Host application
    participant PD as PreferenceData
    participant SQL as SqlHelper
    participant DB as USER_PREFERENCE (Oracle)
    Caller->>PD: SavePreferences(appName, pageName, userId, preferenceText)
    alt preferenceText is empty/whitespace
        PD->>SQL: DeletePref (ScalarQuery)
        SQL->>DB: DELETE
    else preferenceText present
        PD->>SQL: DoesPrefExist (ScalarQuery)
        SQL->>DB: SELECT COUNT(*)
        DB-->>SQL: count
        alt row exists
            PD->>SQL: UpdatePref (ScalarQuery)
            SQL->>DB: UPDATE
        else no row
            PD->>SQL: InsertPref (ScalarQuery)
            SQL->>DB: INSERT (USER_PREFERENCE_SEQ.nextval)
        end
    end
    PD-->>Caller: true

Design constraints

  • Deviation from standard BOF data-access pattern: This library does not implement the standard clsBusinessBase/clsBusinessCollectionBase + IBusinessCriteria object-lifecycle pattern used elsewhere in the framework. There is no nested Criteria class and no CreateSQL/RetrieveSQL/InsertSQL/UpdateSQL/DeleteSQL properties. Instead, PreferenceData issues inline Oracle SQL directly via SqlHelper.ResultSetQuery and SqlHelper.ScalarQuery<T>. This is a deliberate architectural deviation that should be noted by developers expecting the standard business-object model.
  • The library targets a single table (USER_PREFERENCE) with no joins or foreign-key relationships; all 7 cataloged SQL statements (see SQL catalog) reference only this table.
  • The SAIF.Framework dependency is resolved as a compiled binary reference (HintPath) rather than a <ProjectReference>, though the local .sln builds against the sibling SAIF.Framework.Core project's output.*
  • No configuration retrieval mechanism exists in this library (no IEnvironmentService, ConfigurationManager.AppSettings, Web.config/App.config, or DbConnectionManager usage) — the database/portal execution context is entirely supplied by the caller through the injected IDataPortalInfo.
  • No authentication, authorization, or segregation-of-duties logic exists in this library; userId is used purely as a data key for scoping USER_PREFERENCE rows, not as an authorization decision point.
  • Open question — possible duplicate implementation: A separate PreferenceData.vb implementing similar preference persistence exists at SAIF.Framework.Core\Preferences\PreferenceData.vb. That file belongs to SAIF.Framework.Core, not SAIF.Framework.Preferences, and was out of scope for this analysis. Its relationship to this library's PreferenceData (duplicate, legacy predecessor, or independent implementation) is unconfirmed.**

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • SAIF.Framework.Preferences\Preference.cs
  • SAIF.Framework.Preferences\PreferenceData.cs
  • SAIF.Framework.Preferences\SAIF.Framework.Preferences.csproj
  • SAIF.Framework.Core\V1\DataAccessLayer\SqlHelper.vb
  • SAIF.Framework.Core\Preferences\PreferenceData.vb