Table of Contents

Sviluppo su database (data-access)

Guida operativa per lavorare sul livello di accesso ai dati Oracle. Il caso guida (seed) è il verticale RequestCenter / Service Desk; i pattern descritti valgono per gli altri domini che ripetono lo stesso layering DAL. Classificazione per ogni affermazione sostanziale; percorsi in ## Evidenze.

Vedi anche: Schema REQUESTCENTER_TEST38 · Tabelle · Procedure/package · CRUD matrix · API · Dominio Service Desk · FLOW-REQ-001 · Regole BR-REQ · codice: RequestDAL · GlobalDataManager · Transaction.

Modello di accesso ai dati (visione d'insieme)

Il flusso è a strati fissi (VERIFIED, ripetuto in tutte le funzioni ispezionate di RequestDAL.vb):

BL (Descor.RequestCenter)  ->  DAL (Descor.RequestCenter.DAL.OracleODP)  ->  cm (GlobalDataManager)  ->  stored procedure Oracle (package GESTREQUEST / GESTREQUEST_T2)
  • Nessun ORM. Non c'è Entity Framework, Dapper o simili nel verticale RequestCenter: il DAL costruisce a mano OracleParameter e invoca procedure/package Oracle tramite l'helper cm. (SUPPORTED)
  • Nessun SQL inline nelle DAL RC. Una ricerca di stringhe SELECT/INSERT/UPDATE/DELETE letterali in RequestDAL.vb restituisce 0 occorrenze: ogni comando passato a cm è un nome di procedura ("PACKAGE.PROC" o "PROC"). (SUPPORTED)
  • SQL raw: raro/legacy nel resto della codebase; non usato nel percorso RequestCenter ispezionato. Preferire sempre una stored procedure + i metodi cm.* rispetto a SQL scritto a mano. (INFERRED)

Connessione e configurazione

Le connection string non si modificano a mano nei *.exe.config/web.config. Al deploy il servizio InfocadServer/ConnectionsService legge un connections.xml depositato accanto all'eseguibile, rimuove e riscrive la sezione <connectionStrings> del config di destinazione e riavvia il servizio tramite restartserver.bat. (VERIFIED)

  • Nomi di connessione noti a livello di piattaforma: MainConnection (core Infocad), RequestCenterConnection, DEMConnection, OracleProvidersDB (membership/role ASP.NET). (SUPPORTED, da CLAUDE.md)
  • Attenzione (CONFLICTING): il codice RequestCenter risolve la connessione con la chiave letterale "RequestCenter" (Settings.InstantiateConnectionManager), non "RequestCenterConnection". Verificare il nome effettivo nel config dell'app target prima di editare connections.xml.
  • ConnectionsService estrae inoltre l'applicationName (per i provider membership/role Oracle) dallo stesso ConnectionString. (SUPPORTED)

Come il DAL ottiene cm

Ogni funzione DAL apre con:

Dim cm As GlobalDataManager = Configuration.Settings.GetConnectionManager(True)

Settings.GetConnectionManager restituisce un GlobalDataManager per-request (memorizzato in HttpContext.Current.Items("RCCONNECTIONMANAGER"); sul canale WCF usa OperationContext.Current). Il parametro opzionale setDbSession propaga alla sessione DB le chiavi DBUSERSESSION/DBSOURCESESSION (audit dell'utente applicativo). (SUPPORTED)

Driver: Oracle.DataAccess (unmanaged) sotto net48; nella slice net8 (RequestCenter.DAL.OracleODPXNET) una guardia #If NET5_0_OR_GREATER seleziona Oracle.ManagedDataAccess.Core. (SUPPORTED, da CLAUDE.md e brief)

Invocare una stored procedure — pattern cm

GlobalDataManager (progetto DataManager, RootNamespace Descor.DataManager) espone tre famiglie di metodi, ognuna con overload (command), (command, parameter), (command, ParamArray parameters()), (command As DbCommand). (VERIFIED)

Metodo cm Uso Ritorno
ExecuteNonQuery("PKG.PROC", params…) scritture, procedure con OUT scalare Integer (righe/valore)
ExecuteReader("PROC", params…) letture streaming IDataReader
Fill(ds, "PROC", params…) letture in DataSet Integer (righe)

Pattern canonico di scrittura con identità in uscita (esempio addRequest):

Dim newIndexParam As New OracleParameter("NEWREQUESTINDEX", OracleDbType.Int32)
newIndexParam.Direction = ParameterDirection.Output
Try
    openResult = cm.Open
    cm.ExecuteNonQuery("GESTREQUEST_T2.ADDREQUEST", idUserParam, …, newIndexParam)
    Return DirectCast(newIndexParam.Value, Types.OracleDecimal).ToInt32
Finally
    cm.CloseIfNeeded(openResult)
End Try

Pattern canonico di lettura (RefCursor → DataSet), tipicamente con un gemello …DReader (IDataReader):

Dim p_rc As New OracleParameter("DS_CUR", OracleDbType.RefCursor)
p_rc.Direction = ParameterDirection.Output
Try
    openResult = cm.Open
    cm.Fill(ds, "GETREQUESTBYPROTOCOL", protocolParam, p_rc)
    Return ds
Finally
    cm.CloseIfNeeded(openResult)
End Try

Osservazioni ricorrenti (VERIFIED su più funzioni):

  • La gestione connessione è sempre openResult = cm.Open + Finally cm.CloseIfNeeded(openResult) (chiude solo se questa chiamata ha aperto la connessione — riusa una connessione già aperta da una transazione).
  • Il Catch ex As Exception : Throw è racchiuso in #If DEBUG Then: in Release le eccezioni propagano senza il catch esplicito (nessun mascheramento). (SUPPORTED)
  • Le letture RefCursor usano il nome parametro DS_CUR con Direction = Output.

Confini transazionali (RequestCenter.Transaction)

La transazione applicativa si guida dal BL con la classe RequestCenter.Transaction (file RequestCenter/Transaction/Transaction.vb), che delega a un ITransactionDAL ottenuto da DALFactory.GetTransactionDAL:

Dim t As New RequestCenter.Transaction
t.OpenConnection()
t.Begin()
'  … chiamate DAL che riusano lo stesso cm/connessione …
t.Commit()   ' oppure t.Rollback() in caso di errore
t.CloseConnection()
  • Esiste una variante MobileTransaction (delega a DALFactory.GetMobileTransactionDAL). (SUPPORTED)
  • Sotto cm, BeginTransaction accetta un IsolationLevel; l'overload senza argomenti usa il default di Connection.BeginTransaction(). Commit/Rollback sono idempotenti (agiscono solo If InTransaction). Il Dispose/Close(PendingTransactionAction.Rollback) esegue rollback in assenza di commit esplicito. (SUPPORTED)
  • La sequenza OpenConnection → Begin → Commit/Rollback → CloseConnection è quella osservata nel flusso di creazione ticket. (SUPPORTED, vedi FLOW-REQ-001)

Convenzioni

  • Identificatori Oracle in UPPERCASE: package, procedure e nomi parametro sono maiuscoli (GESTREQUEST.ADDDESCRIPTIONTOREQUEST, PIDREQUEST, NEWREQUESTINDEX). (VERIFIED)
  • Prefisso parametri P…: i parametri di input seguono la convenzione P + nome (PIDUSER, PPROTOCOL, PDSREQUEST). (SUPPORTED)
  • Identità via parametro OUT: le insert restituiscono l'id generato con un OracleParameter Direction = Output (es. NEWREQUESTINDEX), letto come Types.OracleDecimal().ToInt32. (VERIFIED)
  • Date/NLS: le date passano come OracleDbType.Date (PREQUESTDATE, Nullable(Of Date)). Per la normalizzazione locale di numeri/formattazione lato DB vedi il reperto BR-ACC-006 (REPLACE(',','.') + NLS_NUMERIC_CHARACTERS='.,'). (SUPPORTED)
  • Mapping enum/stato: gli enum del BL vengono passati come valori interi (es. RequestCollection.GroupOracleDbType.Int16). (SUPPORTED)
  • Concorrenza: non esiste un token di versione a livello DAL; il controllo di modifiche concorrenti è applicativo (confronto ParentLastActivityDate/SiblingLastActivityDate, vedi BR-REQ). (SUPPORTED)
  • Error mapping ORA-: nessuna traduzione/rimappatura di codici ORA-* osservata nel DAL RC — le OracleException propagano invariate al chiamante. (SUPPORTED)

Guide operative

Localizzare il codice che accede a una tabella

  1. Aprire la CRUD matrix o il CSV sorgente stored-procedure-dependencies.csv (REQUESTCENTER/DEM) per trovare le procedure che leggono/scrivono la tabella (colonne READ/WRITE/RW).
  2. Cercare il nome della procedura in RequestDAL.vb (stringa passata a cm.Execute*/cm.Fill) per individuare la Function DAL che la invoca.
  3. Risalire al chiamante BL cercando il metodo IRequestDAL implementato (clausola Implements).

Localizzare le tabelle accessibili da una classe

Partire dalla Function DAL, leggere il nome "PKG.PROC" passato a cm, poi consultare le dipendenze proc→tabella nella CRUD matrix / stored-procedure-dependencies.csv. Non dedurre le tabelle dal nome del metodo.

Aggiungere una lettura

  1. Verificare/creare la stored procedure Oracle che ritorna un RefCursor (OUT).
  2. In RequestDAL.vb, aggiungere una Function che costruisce gli OracleParameter (input P… + DS_CUR RefCursor Output) e chiama cm.Fill(ds, "PROC", …); opzionalmente il gemello …DReader con cm.ExecuteReader.
  3. Dichiarare la firma in IRequestDAL (Interfaces/TicketInterfaces.vb) e aggiungere Implements.
  4. Esporre il metodo dal BL.

Aggiungere una scrittura

Come sopra ma con cm.ExecuteNonQuery("PKG.PROC", …); per l'id generato aggiungere un OracleParameter Direction = Output. Se la scrittura fa parte di una transazione multi-step, orchestrare da BL con RequestCenter.Transaction (OpenConnection/Begin/…/Commit/Rollback/CloseConnection) affinché le Function DAL riusino la stessa connessione (cm.Open non riapre, CloseIfNeeded non chiude).

Aggiungere un parametro a una stored procedure (impatto DAL)

  1. Modificare la procedura Oracle (nuovo parametro, UPPERCASE, prefisso P…).
  2. Aggiornare tutte le Function DAL che invocano quella procedura: nuovo OracleParameter nella lista passata a cm.* (l'ordine posizionale del ParamArray deve corrispondere alla firma della procedura).
  3. Propagare il parametro su IRequestDAL e sui chiamanti BL.
  4. Se la slice net8 rilinka il file (RequestCenter.DAL.OracleODPXNET), il cambiamento è ereditato via <Compile Include … Link=…> (nessuna duplicazione). Nota: RequestCSDAL.vb e RequestCSReasonDAL.vb sono esclusi dalla slice net8.

Testare una modifica di data-access

Nessun test automatico nel repo (0 xUnit/NUnit/MSTest). Le verifiche sono manuali/di integrazione via InfocadServer/InfocadTester o esercitando il flusso dalla UI/WCF. Non dichiarare copertura non misurata. Per un'ispezione read-only dei metadati/dati su TEST38 senza lo stack Windows, usare python-oracledb in thin mode (credenziali dal .env non tracciato; mai stampare segreti). Non osservare/dichiarare comportamento di PROD.

Verificare l'impatto cross-schema (DEM / INFOCAD)

Lo schema REQUESTCENTER_TEST38 ha edge cross-schema in uscita verso DEM_TEST38 (217) e INFOCAD_TEST38 (104): una procedura RequestCenter può leggere/scrivere oggetti di un altro schema. Prima di modificare una procedura o una tabella, controllare le dipendenze cross-schema nell' indice dello schema e nei CSV di dipendenze, per non rompere consumatori in DEM/INFOCAD. (VERIFIED sui conteggi)

Modifiche di schema: non applicarle senza le procedure operative di deploy. La riconfigurazione delle connessioni passa da ConnectionsService + connections.xml + restartserver.bat; coordinarsi con quel processo.

Evidenze

  • InfocadWeb/WebMachine/DataManager/GlobalDataManager.vb:104 (Open), :134 (Close→Rollback), :163 (BeginTransaction(isolationLevel)), :171 (CommitTransaction), :181 (RollbackTransaction), :214-226 (overload ExecuteNonQuery), :297-317 (overload ExecuteReader), :423-473 (overload Fill), :574 (CloseIfNeeded).
  • InfocadWeb/WebMachine/RequestCenter.DAL.OracleODP/RequestDAL.vb:5054 (addRequestGESTREQUEST_T2.ADDREQUEST, OUT NEWREQUESTINDEX), :5089 (overload → GESTREQUEST.ADDREQUESTWITHOUTPROTOCOL), :5407 (setDescriptionGESTREQUEST.ADDDESCRIPTIONTOREQUEST), :633 (getByProtocolFill("GETREQUESTBYPROTOCOL", … DS_CUR)), :657 (getByProtocolDReaderExecuteReader). Ricerca SQL inline (SELECT/INSERT/UPDATE/DELETE letterali) in RequestDAL.vb = 0 occorrenze.
  • InfocadWeb/WebMachine/RequestCenter/Configuration/Settings.vb:242 (GetConnectionManager(setDbSession)), :234/:236 (ConnectionStrings("RequestCenter")New GlobalDataManager(...)), :232 (InstantiateConnectionManager).
  • InfocadWeb/WebMachine/RequestCenter/Transaction/Transaction.vb:3 (Transaction), :5-28 (Begin/Commit/Rollback/OpenConnection/CloseConnectionDALFactory.GetTransactionDAL), :32 (MobileTransaction).
  • InfocadServer/ConnectionsService/Program.cs:37 (connections.xml), :93-94 (RemoveConnectionStrings/AddConnectionStrings), :97-98 (delete connections.xml), :116 (restartserver.bat), :230-244 (AddConnectionStrings, estrazione applicationName).
  • Metadati DB: REQUESTCENTER_TEST38/index.md — edge cross-schema in uscita DEM_TEST38 217 / INFOCAD_TEST38 104 (snapshot 2026-07-21); package GESTREQUEST/GESTREQUEST_T2 in procedures.md.
  • NLS/importi: BR-ACC-006 (VERIFIED). Creazione ticket / OUT id: BR-REQ-013s., FLOW-REQ-001.
  • Metadati progetto: RequestCenter.DAL.OracleODP.vbproj (VB net48, Descor.RequestCenter.DAL.OracleODP, driver Oracle.DataAccess); RequestCenter.DAL.OracleODPXNET (net8, PkgRef Oracle.ManagedDataAccess.Core 23.4.0, guardia #If NET5_0_OR_GREATER, esclude RequestCSDAL.vb/ RequestCSReasonDAL.vb); DataManager (Descor.DataManager). Comandi msbuild/Windows/Oracle Client NON verificati su questo host (macOS); python-oracledb read-only e script portale verificati.