Multi-database portal registration¶
ApplicationDataAccess is the multi-portal registration helper that an AppManagerBase subclass uses (typically from its OnCreateDataLayer() hook) to build one or more keyed IDataPortalInfo entries — one per logical database connection the manager needs — backed by either a SQL Server or an Oracle data portal.
| Field | Value |
|---|---|
| Operation ID | OP-APP-05 |
| Trigger | Consuming code sets DBUser, Database, Server, and/or BatchID on an ApplicationDataAccess instance and calls CreateSQLServerPortal(key) or CreateOraclePortal(key) |
| Inputs | DBUser, Database, Server, BatchID connection properties; the registration key string; optionally a batch user ID supplied to the constructor |
| Outputs | A stored, keyed IDataPortalInfo entry retrievable through the DPI(key) property; the underlying clsDataAccess (DAL) instance used to add the portal |
| Primary components | ApplicationDataAccess.New, ApplicationDataAccess.CreateSQLServerPortal, ApplicationDataAccess.CreateOraclePortal, ApplicationDataAccess.DPI, AppManagerBase.InjectDPI |
| Entry point | Application\SAIF.Application\ApplicationDataAccess.vb |
Steps¶
- Construct the data-access object.
New(Optional inBatchUserID As String = "")initializes a freshclsDataAccess.clsEnvironmentand either: - constructs
clsDataAccess(inBatchUserID)and setsm_Env.ClientID = inBatchUserIDwhen a non-blank batch user ID is supplied, or - constructs the parameterless
clsDataAccessand setsm_Env.ClientID = m_DAL.ClientIDfrom the resulting DAL when no batch user ID is given. - This constructor is normally invoked indirectly, through
AppManagerBase.DataLayer's lazy getter, which passesSecurityPrincipal.UserName.ToStringas the batch user ID — see Application context initialization. - Set connection properties. Consuming code (typically the subclass's
OnCreateDataLayer()) setsDBUser,Database,Server, and optionallyBatchIDon theApplicationDataAccessinstance before registering any portal. These are plain auto-implemented properties with no validation. - Register a SQL Server portal.
CreateSQLServerPortal(inKey As String): - Copies
m_DAL.ClientIDintom_Env.ClientID. - Copies
DBUser,Database, andServerinto the environment. - Sets
m_Env.DBMSType = clsDataAccess.clsEnvironment.DBMS.SqlServer. - If
BatchID.Trim.Length > 0: overwritesm_Env.ClientIDwithBatchID, so a configured batch ID takes precedence over the DAL's own client ID (BR-005). - Constructs
New clsSQLDataPortal(m_Env, True)and adds it tom_DPILibraryunder the lower-cased key, viaDAL.AddDataPortal(portal, portal.PortalID & inKey). - On failure: this method calls
m_DPILibrary.Add(inKey.ToLower, ...)directly rather than through theDPIproperty setter, so it does not perform the duplicate-key guard that theDPIsetter enforces — a second call with the same key raises a runtime "key already exists" exception from the underlyingSortedListinstead of being silently ignored.* - Register an Oracle portal.
CreateOraclePortal(inKey As String)follows the same sequence as step 3 but setsm_Env.DBMSType = clsDataAccess.clsEnvironment.DBMS.Oracle, omits theServerassignment (Oracle connections are identified byDatabaseandDBUseronly in this environment shape), and constructsNew clsMSOracleDataPortal(m_Env)instead of the SQL Server portal type (BR-005). - Same direct-
Addcaveat as step 3 applies — a duplicate key raises an exception rather than being ignored.* - Retrieve a registered portal. Any caller reads
DPI(key)to get the storedIDataPortalInfo, which looks the key up by its lower-cased form inm_DPILibrary. - On failure: requesting a key that was never registered raises a
KeyNotFoundExceptionfrom the underlyingSortedList, since the getter performs no existence check.* - Inject a portal without going through Create*Portal.
AppManagerBase.InjectDPI(inKey, inDPI)setsDataLayer.DPI(inKey) = inDPIdirectly, which — unlike steps 3–4 — routes through theDPIproperty'sFriendsetter. That setter lower-cases the key and only adds the entry whenContainsKeyisFalse, so an injected key that already exists is silently ignored rather than replacing the prior entry or raising (BR-004).
Process flow¶
The following diagram visualizes portal registration for both database types and the two different registration entry points.
flowchart TD
Start([ApplicationDataAccess constructed]) --> SetProps[Set DBUser, Database,<br>Server, BatchID]
SetProps --> Which{SQL Server or Oracle?}
Which -->|SQL Server| SqlEnv[Copy ClientID, DBUser,<br>Database, Server; set DBMS=SqlServer]
Which -->|Oracle| OraEnv[Copy ClientID, DBUser,<br>Database; set DBMS=Oracle]
SqlEnv --> BatchCheck1{BatchID set?}
OraEnv --> BatchCheck2{BatchID set?}
BatchCheck1 -->|Yes| OverrideClient1[ClientID = BatchID]
BatchCheck1 -->|No| KeepClient1[Keep DAL ClientID]
BatchCheck2 -->|Yes| OverrideClient2[ClientID = BatchID]
BatchCheck2 -->|No| KeepClient2[Keep DAL ClientID]
OverrideClient1 --> BuildSql[New clsSQLDataPortal]
KeepClient1 --> BuildSql
OverrideClient2 --> BuildOra[New clsMSOracleDataPortal]
KeepClient2 --> BuildOra
BuildSql --> AddDirect[m_DPILibrary.Add key,<br>duplicate key throws]
BuildOra --> AddDirect
AddDirect --> Stored([Portal available via DPI key]))
InjectPath([AppManagerBase.InjectDPI]) --> Setter[DPI setter: add only<br>if key not already present]
Setter --> Stored
Failure and edge-case behavior¶
CreateSQLServerPortalandCreateOraclePortaladd tom_DPILibrarydirectly instead of through the guardedDPIproperty setter, so registering the same key twice through eitherCreate*Portalmethod throws, while re-injecting the same key throughInjectDPIis silently ignored — the two registration paths are inconsistent with each other (BR-004).*- Neither
CreateSQLServerPortalnorCreateOraclePortalvalidates thatDBUser,Database, orServer(for SQL Server) are non-blank before building the portal — a portal can be constructed from an empty connection environment with no explicit error from this library.* CreateOraclePortalnever setsm_Env.Server, so any previously-setServervalue on the sharedm_Env.clsEnvironmentinstance persists across a mixed sequence of SQL Server and Oracle portal creation calls on the sameApplicationDataAccessinstance, sincem_Envis reused rather than recreated per call.*- Reading
DPI(key)for an unregistered key raises aKeyNotFoundException; there is noTryGetValue-style accessor exposed by this class.*
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¶
Application\SAIF.Application\ApplicationDataAccess.vbApplication\SAIF.Application\AppManagerBase.vb