Table of Contents

RequestCenter.Transaction

Unità di lavoro (unit-of-work) del layer BL di RequestCenter: incapsula il ciclo di vita della connessione Oracle condivisa cm (GlobalDataManager) e la transazione che vi si appoggia, esponendo OpenConnection/Begin/Commit/Rollback/CloseConnection. Classificazione complessiva: VERIFIED (sorgente Transaction.vb + implementazione DAL + uso reale in makeTicket.ascx.vb).

Scopo

Transaction è una facade sottile che il codice di presentazione (code-behind) usa per delimitare una scrittura atomica su Oracle: apre la connessione, avvia la transazione, e dopo il lavoro del BL/DAL decide Commit o Rollback, chiudendo infine la connessione. Non contiene logica di dominio né SQL: delega interamente all'implementazione DAL risolta a runtime, che a sua volta pilota il GlobalDataManager condiviso della richiesta. Classificazione: VERIFIED (Transaction.vb:3-30; TransactionDAL.vb:12-43).

Namespace e progetto

  • Tipo: Transaction (globale rispetto alla radice Descor.RequestCenter, dichiarato senza blocco Namespace in Transaction.vb; usato come RequestCenter.Transaction dal web). SUPPORTED (Transaction.vb:3; uso qualificato in makeTicket.ascx.vb:88).
  • Progetto: RequestCenter (RequestCenter.vbproj, VB.NET net48, RootNamespace Descor.RequestCenter), file Transaction/Transaction.vb.
  • Interfaccia di contratto: Descor.RequestCenter.Interfaces.Transaction.ITransactionDAL (Interfaces/TransactionInterfaces.vb:3).
  • Implementazione DAL: TransactionDAL / MobileTransactionDAL nel progetto RequestCenter.DAL.OracleODP (TransactionDAL.vb:12,45).

Nello stesso file convive MobileTransaction, gemello identico che si differenzia solo per la factory DAL usata (GetMobileTransactionDAL invece di GetTransactionDAL). VERIFIED (Transaction.vb:32-59).

Responsabilità

  • Aprire e chiudere la connessione Oracle di richiesta (OpenConnection/CloseConnection).
  • Avviare, confermare o annullare la transazione (Begin/Commit/Rollback).
  • Fare da punto di ingresso stabile per il code-behind, disaccoppiandolo dal DAL concreto (risolto per reflection dalla DALFactory).

Non è responsabile di: aprire connessioni per singola query (lo fa il DAL di dominio tramite lo stesso cm), scegliere l'IsolationLevel (delegato a GlobalDataManager), o eseguire SQL.

Perché esiste

UNKNOWN — non è documentata nel sorgente una motivazione storica/di business esplicita. Il ruolo tecnico (facade unit-of-work sul GlobalDataManager condiviso) è invece supportato dal codice; vedi Scopo e Ciclo di vita.

Contratto pubblico

Cinque Public Sub senza parametri né valore di ritorno, tutti a delega diretta verso ITransactionDAL (VERIFIED, Transaction.vb:5-28):

Membro Delega a Effetto sul GlobalDataManager
OpenConnection() ITransactionDAL.OpenConnection cm.Open() — apre se Connection.State = Closed
Begin() ITransactionDAL.Begin cm.BeginTransaction() se Not cm.InTransaction
Commit() ITransactionDAL.Commit cm.CommitTransaction() se cm.InTransaction
Rollback() ITransactionDAL.Rollback cm.RollbackTransaction() se cm.InTransaction
CloseConnection() ITransactionDAL.CloseConnection cm.Close() — chiude la connessione

ITransactionDAL eredita IBaseDAL e dichiara esattamente questi cinque Sub (VERIFIED, TransactionInterfaces.vb:3-11).

Implementazioni o classi derivate

  • TransactionDAL (Inherits BaseDAL, Implements ITransactionDAL) — implementazione Oracle standard. VERIFIED (TransactionDAL.vb:12-43).
  • MobileTransactionDAL — implementazione identica riga per riga, distinta come tipo separato per il canale "mobile". VERIFIED (TransactionDAL.vb:45-76).
  • MobileTransaction (BL) — facade gemella di Transaction che instrada verso MobileTransactionDAL. VERIFIED (Transaction.vb:32-59).

Dipendenze

  • DALFactory.GetTransactionDAL() / GetMobileTransactionDAL() — risolvono l'implementazione per reflection: caricano l'assembly DAL (Configuration.Settings.DALTypeName, con suffisso XNET sotto net8) e istanziano il tipo …TransactionDAL via Activator.CreateInstance, memorizzandolo in un dizionario statico _instances. VERIFIED (DALFactory.vb:36-41,159-165).
  • Configuration.Settings.GetConnectionManager() — fornisce il GlobalDataManager (cm) condiviso, conservato in HttpContext.Current.Items("RCCONNECTIONMANAGER") (uno per richiesta HTTP; fallback WCF OperationContext). VERIFIED (Settings.vb:242-296).
  • GlobalDataManager (progetto DataManager) — motore effettivo di connessione/transazione. Vedi class-GlobalDataManager.md.
  • Driver Oracle: Oracle.DataAccess (unmanaged) sotto net48; Oracle.ManagedDataAccess sotto net8 (guardia #If NET5_0_OR_GREATER). VERIFIED (TransactionDAL.vb:3-10).

Ciclo di vita

La facade è stateless: Dim dal As ITransactionDAL = DALFactory.GetTransactionDAL viene richiamata a ogni metodo (VERIFIED, Transaction.vb:6,11,16,21,26). Lo stato reale (connessione + transazione) vive nel GlobalDataManager di richiesta, non nell'istanza Transaction.

Ciclo tipico osservato nel flusso di creazione ticket (makeTicket.ascx.vb, VERIFIED):

  1. Dim objTransaction As New RequestCenter.Transaction:88.
  2. objTransaction.OpenConnection():111cm.Open().
  3. objTransaction.Begin():112cm.BeginTransaction().
  4. Lavoro BL/DAL nella stessa richiesta (Request.Create, SetWorkflowInterface, …) sullo stesso cm.
  5. objTransaction.Commit():216cm.CommitTransaction().
  6. In caso di eccezione: objTransaction.Rollback() nel blocco Catch:240.
  7. objTransaction.CloseConnection() nel blocco Finally:254cm.Close().

L'istanza DAL sottostante, invece, non è per-richiesta: DALFactory la memorizza in cache statica e la riusa per l'intero processo (vedi Thread safety).

Stato interno

  • Transaction / MobileTransaction: nessun campo. VERIFIED (Transaction.vb:3-59).
  • TransactionDAL / MobileTransactionDAL: unico campo Private _cm As GlobalDataManager = Nothing, inizializzato pigramente al primo metodo invocato (If _cm Is Nothing Then _cm = Configuration.Settings.GetConnectionManager) e mai reimpostato. VERIFIED (TransactionDAL.vb:16,19,24,29,34,39).

Metodi principali

Tutti i metodi sono a corpo unico e delegano al DAL; non richiedono un method-block dettagliato. Il comportamento significativo è nel DAL (TransactionDAL.vb):

  • Begin → apre la transazione solo se non già attiva (If Not _cm.InTransaction Then _cm.BeginTransaction()); BeginTransaction a sua volta apre la connessione se chiusa. VERIFIED (TransactionDAL.vb:18-21; GlobalDataManager.vb:155-161).
  • Commit / Rollback → agiscono solo se _cm.InTransaction, poi Dispose della transazione e azzeramento del riferimento. VERIFIED (TransactionDAL.vb:23-31; GlobalDataManager.vb:171-189).
  • CloseConnection_cm.Close(); l'overload di default di GlobalDataManager.Close() esegue Close(PendingTransactionAction.Rollback), quindi annulla qualunque transazione ancora pendente prima di chiudere la connessione. VERIFIED (TransactionDAL.vb:33-36; GlobalDataManager.vb:133-149).

Collaborazioni

  • BL e DAL condividono lo stesso cm: Transaction e i DAL di dominio (es. RequestDAL) ottengono entrambi il GlobalDataManager da Configuration.Settings.GetConnectionManager, che ritorna l'oggetto unico di HttpContext.Current.Items("RCCONNECTIONMANAGER"). Perciò la transazione aperta da Transaction.Begin() copre le scritture eseguite dai DAL nella medesima richiesta HTTP, senza passaggio esplicito di connessione. INFERRED (condivisione via chiave RCCONNECTIONMANAGER, Settings.vb:245,285-295; il passaggio del cm ai singoli DAL è documentato in class-RequestDAL.md).
  • Code-behind chiamante: makeTicket.ascx.vb (Descor.RequestCenterWeb.makeTicket). VERIFIED (makeTicket.ascx.vb:88-255).

Accesso al database

Nessun accesso diretto. Transaction non nomina package, stored procedure o tabelle: apre/chiude connessione e transazione. Le scritture della richiesta (package GESTREQUEST/GESTREQUEST_T2 ecc.) sono eseguite dai DAL di dominio all'interno della finestra transazionale. Vedi la matrice DB in REQUESTCENTER_TEST38 e la crud-matrix.

Transazioni

La gestione transazionale è interamente delegata a GlobalDataManager:

  • Begin usa l'overload senza IsolationLevel (Connection.BeginTransaction()), quindi vale il livello di isolamento di default del provider/DB Oracle; Transaction non lo imposta. Esiste in GlobalDataManager un overload BeginTransaction(isolationLevel As IsolationLevel), ma la facade non lo invoca. VERIFIED (GlobalDataManager.vb:155-169; TransactionDAL.vb:20).
  • Idempotenza: Begin/Commit/Rollback sono protetti dal guardiano InTransaction, quindi chiamate ridondanti sono no-op (non sollevano eccezione). VERIFIED (TransactionDAL.vb:20,25,30).

Autorizzazione

Nessun controllo di autorizzazione in questa classe. Il gating dell'operazione (contesto utente, PreInit di pagina) è a monte, nel web tier.

Side effect

  • Apre/chiude una connessione Oracle fisica sul GlobalDataManager di richiesta. VERIFIED (GlobalDataManager.vb:104-149).
  • Open() con DbSessionParams valorizzati esegue la stored procedure SET_CONTEXT_VALUE per impostare il contesto di sessione DB (utente/sorgente). SUPPORTED (GlobalDataManager.vb:113-117).
  • Commit/Rollback fanno Dispose dell'oggetto transazione. VERIFIED (GlobalDataManager.vb:176,186).

Gestione degli errori

  • La facade non intercetta eccezioni: eventuali errori del DAL/GlobalDataManager risalgono al chiamante. VERIFIED (Transaction.vb:5-28).
  • La disciplina di rollback è nel chiamante: nel flusso ticket il Rollback è nel Catch (makeTicket.ascx.vb:240) e CloseConnection nel Finally (:254).
  • Rete di sicurezza: anche se il chiamante omettesse il Rollback, CloseConnectioncm.Close() annulla la transazione pendente di default. VERIFIED (GlobalDataManager.vb:133-149).
  • Se il GlobalDataManager è già _disposed, i suoi metodi sollevano ObjectDisposedException. VERIFIED (GlobalDataManager.vb:75,107,138,156,172,182).

Thread safety

  • L'istanza Transaction/MobileTransaction è stateless: non condivide stato tra thread.
  • Il GlobalDataManager sottostante è request-scoped (HttpContext.Current.Items), quindi non condiviso tra richieste HTTP concorrenti. INFERRED (Settings.vb:244-245).
  • Concern (INFERRED): l'istanza TransactionDAL è un singleton di processo (cache statica DALFactory._instances, DALFactory.vb:36-41) e il suo campo _cm viene valorizzato una sola volta al primo utilizzo (If _cm Is Nothing …) e mai rinnovato. Sotto più richieste concorrenti, _cm resta legato al GlobalDataManager della prima richiesta invece che a quello della richiesta corrente ottenibile da GetConnectionManager. Non è stato osservato un meccanismo che azzeri _cm per richiesta; l'effetto è un potenziale disallineamento tra la connessione usata dal Transaction/DAL di dominio e quella attesa. Da verificare con esecuzione reale (non possibile su questo host). Vedi Debito tecnico.

Considerazioni sulle prestazioni

Il riuso della connessione di richiesta (una Open/Close per unità di lavoro anziché per query) riduce l'apertura ripetuta di connessioni Oracle. Nessun altro impatto rilevabile staticamente.

Esempio di utilizzo

Convenzione reale dal flusso di creazione ticket (verificata staticamente, non eseguita su questo host):

Dim objTransaction As New RequestCenter.Transaction
Try
    objTransaction.OpenConnection()          ' :111
    objTransaction.Begin()                    ' :112
    ' ... scritture BL/DAL sullo stesso cm ...
    objTransaction.Commit()                   ' :216
Catch ex As Exception
    objTransaction.Rollback()                 ' :240
    ' logging / refresh cache ...
Finally
    objTransaction.CloseConnection()          ' :254
End Try

Test correlati

Nessun test automatico nel repository (0 test in tutta la codebase). Copertura non misurata.

Flussi correlati

Regole di business correlate

Limitazioni

  • IsolationLevel non selezionabile tramite questa facade (usa il default del provider).
  • Nessun TransactionScope/enlistment distribuito: la transazione è locale alla singola OracleConnection del GlobalDataManager.

Debito tecnico

  • Duplicazione integrale tra Transaction/MobileTransaction e tra TransactionDAL/MobileTransactionDAL (corpi identici, unica differenza la factory). VERIFIED (Transaction.vb:3-59; TransactionDAL.vb:12-76).
  • Campo _cm del DAL singleton mai rinnovato (vedi Thread safety). INFERRED.

Evidenze

  • InfocadWeb/WebMachine/RequestCenter/Transaction/Transaction.vb:3 (class Transaction), :5-28 (metodi delega), :32-59 (MobileTransaction).
  • InfocadWeb/WebMachine/RequestCenter/Interfaces/TransactionInterfaces.vb:1-13 (namespace Interfaces.Transaction, ITransactionDAL a :3, Inherits IBaseDAL).
  • InfocadWeb/WebMachine/RequestCenter.DAL.OracleODP/TransactionDAL.vb:12-43 (TransactionDAL), :45-76 (MobileTransactionDAL); campo _cm :16,49; guardie driver :3-10.
  • InfocadWeb/WebMachine/RequestCenter/DALFactory.vb:36-41 (GetInstanceOfType + cache _instances), :159-165 (GetTransactionDAL/GetMobileTransactionDAL).
  • InfocadWeb/WebMachine/RequestCenter/Configuration/Settings.vb:242-296 (GetConnectionManager, chiave RCCONNECTIONMANAGER).
  • InfocadWeb/WebMachine/DataManager/GlobalDataManager.vb:81-87 (InTransaction), :104-149 (Open/Close), :155-189 (BeginTransaction/overload IsolationLevel/CommitTransaction/RollbackTransaction).
  • InfocadWeb/WebMachine/CASSANDRA/RequestCenterWeb/UserControls/FlowActions/makeTicket.ascx.vb:82 (btnPost_Click), :88 (New RequestCenter.Transaction), :111 OpenConnection, :112 Begin, :216 Commit, :240 Rollback, :252-255 Finally/CloseConnection.
  • Oggetti DB: connessione Oracle via GlobalDataManager (nessuna stored procedure invocata direttamente da Transaction; SET_CONTEXT_VALUE invocata da GlobalDataManager.Open quando presenti DbSessionParams).