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
OracleParametere invoca procedure/package Oracle tramite l'helpercm. (SUPPORTED) - Nessun SQL inline nelle DAL RC. Una ricerca di stringhe
SELECT/INSERT/UPDATE/DELETEletterali inRequestDAL.vbrestituisce 0 occorrenze: ogni comando passato acmè 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 editareconnections.xml. ConnectionsServiceestrae inoltre l'applicationName(per i provider membership/role Oracle) dallo stessoConnectionString. (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_CURconDirection = 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 aDALFactory.GetMobileTransactionDAL). (SUPPORTED) - Sotto
cm,BeginTransactionaccetta unIsolationLevel; l'overload senza argomenti usa il default diConnection.BeginTransaction(). Commit/Rollback sono idempotenti (agiscono soloIf InTransaction). IlDispose/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 convenzioneP+ nome (PIDUSER,PPROTOCOL,PDSREQUEST). (SUPPORTED) - Identità via parametro
OUT: le insert restituiscono l'id generato con unOracleParameterDirection = Output(es.NEWREQUESTINDEX), letto comeTypes.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.Group→OracleDbType.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 — leOracleExceptionpropagano invariate al chiamante. (SUPPORTED)
Guide operative
Localizzare il codice che accede a una tabella
- 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). - Cercare il nome della procedura in
RequestDAL.vb(stringa passata acm.Execute*/cm.Fill) per individuare la Function DAL che la invoca. - Risalire al chiamante BL cercando il metodo
IRequestDALimplementato (clausolaImplements).
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
- Verificare/creare la stored procedure Oracle che ritorna un RefCursor (
OUT). - In
RequestDAL.vb, aggiungere una Function che costruisce gliOracleParameter(inputP…+DS_CURRefCursorOutput) e chiamacm.Fill(ds, "PROC", …); opzionalmente il gemello…DReaderconcm.ExecuteReader. - Dichiarare la firma in
IRequestDAL(Interfaces/TicketInterfaces.vb) e aggiungereImplements. - 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)
- Modificare la procedura Oracle (nuovo parametro, UPPERCASE, prefisso
P…). - Aggiornare tutte le Function DAL che invocano quella procedura: nuovo
OracleParameternella lista passata acm.*(l'ordine posizionale delParamArraydeve corrispondere alla firma della procedura). - Propagare il parametro su
IRequestDALe sui chiamanti BL. - Se la slice net8 rilinka il file (
RequestCenter.DAL.OracleODPXNET), il cambiamento è ereditato via<Compile Include … Link=…>(nessuna duplicazione). Nota:RequestCSDAL.vbeRequestCSReasonDAL.vbsono 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(overloadExecuteNonQuery),:297-317(overloadExecuteReader),:423-473(overloadFill),:574(CloseIfNeeded).InfocadWeb/WebMachine/RequestCenter.DAL.OracleODP/RequestDAL.vb:5054(addRequest→GESTREQUEST_T2.ADDREQUEST, OUTNEWREQUESTINDEX),:5089(overload →GESTREQUEST.ADDREQUESTWITHOUTPROTOCOL),:5407(setDescription→GESTREQUEST.ADDDESCRIPTIONTOREQUEST),:633(getByProtocol→Fill("GETREQUESTBYPROTOCOL", … DS_CUR)),:657(getByProtocolDReader→ExecuteReader). Ricerca SQL inline (SELECT/INSERT/UPDATE/DELETEletterali) inRequestDAL.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/CloseConnection→DALFactory.GetTransactionDAL),:32(MobileTransaction).InfocadServer/ConnectionsService/Program.cs:37(connections.xml),:93-94(RemoveConnectionStrings/AddConnectionStrings),:97-98(deleteconnections.xml),:116(restartserver.bat),:230-244(AddConnectionStrings, estrazioneapplicationName).- Metadati DB:
REQUESTCENTER_TEST38/index.md— edge cross-schema in uscitaDEM_TEST38217 /INFOCAD_TEST38104 (snapshot 2026-07-21); packageGESTREQUEST/GESTREQUEST_T2inprocedures.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, driverOracle.DataAccess);RequestCenter.DAL.OracleODPXNET(net8, PkgRefOracle.ManagedDataAccess.Core 23.4.0, guardia#If NET5_0_OR_GREATER, escludeRequestCSDAL.vb/RequestCSReasonDAL.vb);DataManager(Descor.DataManager). Comandimsbuild/Windows/Oracle Client NON verificati su questo host (macOS);python-oracledbread-only e script portale verificati.