Table of Contents

FLOW-CEN-001 — Salvataggio di una compilazione (rilevazione/scheda di censimento) — Census

Flusso end-to-end di creazione di una nuova compilazione di censimento (rilevazione compilata a partire da una scheda di valutazione/Evalsheet) del modulo Census / CensusCenter. Path pilota: click su Salva nel controllo CompilationView.ascx (compilazione interattiva da parte di un operatore). Le risposte compilate vengono serializzate in un documento XML e persistite nella tabella CENSUS_XML di Oracle INFOCAD_TEST38 tramite la stored procedure CNS_NEWCOMPILATION_XML (nessun ORM). Il layer BL è raggiunto via .NET Remoting, non in-process.

  • Flow ID: FLOW-CEN-001
  • Repository: InfocadWeb (ASP.NET Web Forms, C#, CensusCenterWeb) + InfocadServer (CensusControllers/CensusBL/CensusDAL, C#)
  • Confidence complessiva: VERIFIED (catena UI → controller → BL → DAL → stored procedure → tabella, confermata su codice E su sorgente DB Oracle)

Obiettivo di business

Consentire a un operatore di censimento di compilare e salvare una rilevazione (scheda/Evalsheet) associata a un'entità di patrimonio (Edificio, Piano, UI). L'operatore seleziona l'entità e la scheda tramite il wizard CompilationCreate, risponde alle domande (CensusRadCheckAnswer/CensusRadOpenAnswer) e al salvataggio le risposte vengono serializzate in XML e archiviate come nuova riga in CENSUS_XML, con id utente, entità, data di compilazione ed eventuale nota. Al termine esiste una nuova compilazione identificata dal proprio ID.

Attori

  • Operatore Census (utente autenticato con grant 20200 sul modulo compilazioni, oppure SuperAdmin) — path interattivo CompilationView.ascx. Il permesso di editing/salvataggio è dato da CanEdit = WS.SessionProfile.SuperAdmin || HasUserGrant(20200) (CompilationView.ascx.cs:132-138).
  • Layer BL remoto Descor.Census.CensusBL.CompilationBL — ospitato come servizio .NET Remoting (Windows service), raggiunto dai controller lato web.
  • Oracle INFOCAD_TEST38 (hub anagrafico; procedura CNS_NEWCOMPILATION_XML, tabella CENSUS_XML).

Trigger

Click sul pulsante Salva (CommandName = "SAVE") della toolbar RadToolBar della scheda di compilazione: evento RadTB_ButtonClick in CompilationView.ascx.cs:640, ramo if (cmdName.Equals("SAVE")) (:643). Il pulsante è visibile solo se CanEdit è vero (CompilationView.ascx.cs:351).

Frontend entry point

  • Shell / creazione: wizard CensusCenterWeb/UserControls/Compilation/CompilationCreate.aspx (CompilationCreate.aspx.cs) — selezione a cascata Distretto → Edificio → Piano/UI + scelta Evalsheet, poi caricamento dei controlli dinamici della scheda (CVUserControl.LoadDynamicControls(), :414).
  • Control scheda / salvataggio: CensusCenterWeb/UserControls/Compilation/CompilationView.ascx (CompilationView.ascx.cs) — rendering domande/risposte e pulsante Salva.
  • Pagina host per visualizzazione/riapertura: CompilationViewPage.aspx (CompilationViewPage.aspx.cs:21-24).
  • Gate di accesso: CanEdit (grant 20200 o SuperAdmin) lato UI (CompilationView.ascx.cs:132-138).

Sequenza principale (main sequence)

  1. L'operatore compila la scheda (risposte check/aperte) e preme Salva.
  2. CompilationView.ascx.csRadTB_ButtonClick (:640) intercetta il comando SAVE (:643) e costruisce l'XML della compilazione con CreateCensusXML(pnlContentCenter) (:645, corpo :572-633): elemento radice <compilation> con <entity>, <user> e <answers> (una <answer> per ogni CensusRadCheckAnswer :600-614 e CensusRadOpenAnswer :616-630, con linkedToField/linkedToTable).
  3. Istanzia il controller CompilationController (:646) e discrimina nuovo vs esistente: isNew = IdCompilation < 1 (:648). Se IdCompilation > 0Update_XML(...) (:651); altrimenti → Save_XML((Guid)WS.SessionLogin.ProviderUserKey, IdEntity, Entity, xml, Description) (:653).
  4. CompilationController.Save_XML (CompilationController.vb/.cs:19) inoltra alla BL castando base.DAO a ICompilationBL: ((ICompilationBL)base.DAO).Save_XML(...) (:21).
    • base.DAO è ottenuto in costruttore via DaoActivate(enControllers.Ctrl_Compilation) (CompilationController.cs:17Ctrl_Base.DaoActivate Ctrl_Base.cs:20-23), che chiama DAOFactory.CreateDAO (DAOFactory.cs:26-27): Activator.GetObject(typeof(ICompilationBL), CHANNEL://SERVERADDRESS/Service_Compilation) — proxy .NET Remoting verso il servizio BL.
  5. CompilationBL.Save_XML (CompilationBL.cs:13-16) delega al DAL: CensusDALFactory.GetCompilationDAL().Save_XML(provUserKey, idEntity, entity, xml, note).
  6. CompilationDAL.Save_XML (CompilationDAL.cs:22-53) prepara i parametri Oracle (PIDUSER Raw, PIDENTITY Int32, PENTITY Varchar2, PXML XmlType, PNOTE Varchar2, PIDCOMPILATION OUT Int32) e invoca dl.ExecuteNonQueryStoredProcedure("CNS_NEWCOMPILATION_XML") (:42); ritorna PIDCOMPILATION (nuovo id) via OracleDecimal.ToInt32() (:43), oppure -1 in caso di esito falso.
  7. Oracle CNS_NEWCOMPILATION_XML (INFOCAD_TEST38): esegue INSERT INTO CENSUS_XML (IDENTITY, ENTITY, IDUSER, COMPILATION_DATE, XML, DESCRIPTION) VALUES (PIDENTITY, PENTITY, PIDUSER, SYSDATE, PXML, PNOTE) RETURNING ID INTO PIDCOMPILATION (src:9-12). COMPILATION_DATE = SYSDATE; ISCANCELLED prende il DEFAULT 0.
  8. Il nuovo id ritorna fino alla UI: IdCompilation = ctrl.Save_XML(...) (:653).
  9. Post-salvataggio (CompilationView.ascx.cs:655-666): se isNew && IdCompilation > 0 la UI notifica il salvataggio; ValidateRequiredQuestion distingue solo tra messaggio "salvato" e "salvato con avviso" (domande obbligatorie non compilate) — non blocca il salvataggio (:657-660). Viene impostato _windowarg = 'true' e _forceLoadData = true (:662-663).

API / service

  • Path interattivo: postback ASP.NET Web Forms sulla scheda (nessun SOAP/WCF diretto verso il DB).
  • Confine di processo: fra web e BL c'è .NET Remoting (Activator.GetObject, DAOFactory.cs:26-27), non una chiamata in-process a DLL. Il contratto remoto è ICompilationBL (CensusInterface/ICompilationBL.cs).
  • Metodi del contratto: Save_XML (create), Update_XML (update), LoadCompilations_XML (read), Delete_XML (delete logico/fisico).

Backend

  • UI/Code-behind: CompilationCreate.aspx.cs (wizard), CompilationView.ascx.cs (scheda + Salva).
  • Controller: Descor.Census.CensusControllers.CompilationController (CensusControllers/CompilationController.cs), base Ctrl_EntityBase/Ctrl_Base con proxy remoto DAO.
  • BL (servizio remoto): Descor.Census.CensusBL.CompilationBL (CensusBL/CompilationBL.cs).
  • DAL: Descor.Census.CensusDAL.OracleODP.CompilationDAL (CensusDAL/OracleODP/CompilationDAL.cs), factory CensusDALFactory.GetCompilationDAL().
  • Pattern DAL: using (DataLayer dl = new DataLayer(ConnectionName))dl.Parameters.Add(OracleParameter...)dl.ExecuteNonQueryStoredProcedure("CNS_NEWCOMPILATION_XML"); id di ritorno via parametro OUT PIDCOMPILATION.

Query / stored procedure

Passo Stored procedure (Oracle) Chiamata da (DAL)
Insert compilazione (nuova) INFOCAD_TEST38.CNS_NEWCOMPILATION_XML (OUT PIDCOMPILATION) CompilationDAL.cs:42
Update compilazione (path alternativo) INFOCAD_TEST38.CNS_UPDATECOMPILATION_XML CompilationDAL.cs:79
Load compilazione per id (READ) INFOCAD_TEST38.CNS_LOADCOMPILATION_XML CompilationDAL.cs:111
Load compilazioni per entità (READ) INFOCAD_TEST38.CNS_LOADCOMPILATION_BYENTITY CompilationDAL.cs:146
Cancellazione (path alternativo) INFOCAD_TEST38.CNS_DELETECOMPILATION_XML CompilationDAL.cs:169

Tabelle lette (read)

  • Nel path di salvataggio (CNS_NEWCOMPILATION_XML): nessuna lettura — la procedura esegue solo l'INSERT.
  • A monte, per popolare il wizard (CompilationCreate.aspx.cs): letture indirette via controller Property (DistrictController, BuildingController, FloorController, UIController) e EvalsheetController (fuori dal confine di questo flusso di WRITE).

Tabelle modificate (write)

  • INFOCAD_TEST38.CENSUS_XMLINSERT di una riga (nuova compilazione): colonne IDENTITY, ENTITY, IDUSER, COMPILATION_DATE (=SYSDATE), XML (XMLTYPE), DESCRIPTION; ID generato via RETURNING ID; ISCANCELLED = DEFAULT 0.

Validazione

  • Autorizzazione: pulsante Salva reso/abilitato solo se CanEdit (SuperAdmin o grant 20200) — CompilationView.ascx.cs:132-138, :351.
  • Validazione dati: nel wizard validateData() richiede la selezione di un'entità (Edificio/Piano/UI) e di una scheda Evalsheet prima di procedere (CompilationCreate.aspx.cs:348-351, :388).
  • Domande obbligatorie: ValidateRequiredQuestion (CompilationView.ascx.cs:554-562) è non bloccante al salvataggio: evidenzia in rosso le domande obbligatorie mancanti e determina solo il messaggio ("salvato" vs "salvato con avviso"), ma la INSERT avviene comunque.
  • Lato DB: nessuna validazione applicativa nella procedura; vincoli garantiti da NOT NULL sulle colonne IDENTITY, ENTITY, IDUSER, COMPILATION_DATE di CENSUS_XML.

Side effects

  • Creazione di una nuova riga in CENSUS_XML con timestamp server (SYSDATE).
  • Ritorno del nuovo ID alla UI (IdCompilation), usato per eventuali Update_XML/note successive.
  • Refresh della UI (_forceLoadData = true, _windowarg = 'true') e notifica utente.
  • Logging eccezioni via Descor.Infrastructure.LogManager.ExceptionLogger.LogException in caso di errore DAL.

Percorsi alternativi / errore

  • Update: se IdCompilation > 0 (compilazione già esistente) → Update_XML (:651) → CNS_UPDATECOMPILATION_XML, che aggiorna in modo condizionale i soli campi valorizzati (IDUSER/IDENTITY/ENTITY/XML+COMPILATION_DATE/DESCRIPTION) su ID = PID (src:9-41).
  • Salvataggio sola nota: ucNote_onDescriptionSaved (:699-726) chiama Update_XML con PIDUSER=NULL, PIDENTITY=0, PENTITY=NULL, PXML=NULL → aggiorna solo DESCRIPTION.
  • Errore DAL: ExecuteNonQueryStoredProcedure falso ⇒ Save_XML ritorna -1; eccezioni loggate e rilanciate (CompilationDAL.cs:48-52). Lato UI, esito negativo ⇒ messaggio ErrorCensusSaved (:666).
  • Copia di una compilazione: il wizard supporta IDCOMPILATION in querystring per precaricare l'XML di una compilazione esistente (CompilationCreate.aspx.cs:417-423), che viene poi salvata come nuova.

Diagramma di sequenza

sequenceDiagram
    actor Op as Operatore Census
    participant UI as CompilationView.ascx.cs
    participant Ctrl as CompilationController
    participant Rem as .NET Remoting
    participant BL as CompilationBL (servizio)
    participant DAL as CompilationDAL
    participant DB as Oracle CNS_NEWCOMPILATION_XML
    participant T as CENSUS_XML

    Op->>UI: Click "Salva" (RadTB_ButtonClick / SAVE)
    UI->>UI: CreateCensusXML() -> XML risposte
    UI->>Ctrl: Save_XML(provUserKey, idEntity, entity, xml, note)
    Ctrl->>Rem: Activator.GetObject(ICompilationBL)
    Rem->>BL: Save_XML(...)
    BL->>DAL: CensusDALFactory.GetCompilationDAL().Save_XML(...)
    DAL->>DB: ExecuteNonQueryStoredProcedure("CNS_NEWCOMPILATION_XML")
    DB->>T: INSERT ... RETURNING ID INTO PIDCOMPILATION
    T-->>DB: ID nuovo
    DB-->>DAL: PIDCOMPILATION (OUT)
    DAL-->>BL: int idCompilation
    BL-->>Ctrl: idCompilation
    Ctrl-->>UI: idCompilation
    UI-->>Op: Notifica "Documento salvato" + refresh

Matrice di tracciabilità (file:riga)

# Componente File Riga Tipo evidenza
1 Trigger Salva InfocadWeb/.../CensusCenterWeb/UserControls/Compilation/CompilationView.ascx.cs 640-668 Codice
2 Gate CanEdit (grant 20200) idem 132-138, 351 Codice
3 Serializzazione XML risposte idem 572-633 Codice
4 Chiamata Save_XML (create) idem 653 Codice
5 Controller Save_XML InfocadServer/CensusControllers/CompilationController.cs 19-22 Codice
6 DaoActivate (Ctrl_Compilation) InfocadServer/CensusControllers/CompilationController.cs 17 Codice
7 Proxy Remoting (Activator.GetObject) InfocadServer/CensusControllers/private/DAOFactory.cs 26-27 Codice
8 BL Save_XML InfocadServer/CensusBL/CompilationBL.cs 13-16 Codice
9 DAL Save_XML + parametri + SP InfocadServer/CensusDAL/OracleODP/CompilationDAL.cs 22-53 (SP call :42) Codice
10 SP INSERT su CENSUS_XML Oracle USER_SOURCE CNS_NEWCOMPILATION_XML 9-12 DB (sorgente)
11 Schema tabella CENSUS_XML Oracle USER_TAB_COLUMNS DB (schema)
12 SP Update (alternativo) Oracle USER_SOURCE CNS_UPDATECOMPILATION_XML 9-41 DB (sorgente)

Evidenza (INLINE)

Codice applicativo (InfocadWeb + InfocadServer)

CompilationView.ascx.cs:640-666 (trigger + create/update + XML):

protected void RadTB_ButtonClick(object sender, RadToolBarEventArgs e)
{
    String cmdName = ((RadToolBarButton)e.Item).CommandName;
    if (cmdName.Equals("SAVE"))
    {
        String xml = CreateCensusXML(pnlContentCenter);
        Census.CensusControllers.CompilationController ctrl = new Census.CensusControllers.CompilationController();
        bool result = false;
        bool isNew = IdCompilation < 1;
        if (IdCompilation > 0)
            result = ctrl.Update_XML(IdCompilation, (Guid)WS.SessionLogin.ProviderUserKey, IdEntity, Entity, xml, Description);
        else
            IdCompilation = ctrl.Save_XML((Guid)WS.SessionLogin.ProviderUserKey, IdEntity, Entity, xml, Description);
        if (result || (isNew && IdCompilation > 0)) { ... NotifyMessage(...DocumentSaved...) ... }
        else NotifyMessage(...ErrorCensusSaved...);
    }
}

CompilationView.ascx.cs:132-138 (autorizzazione):

public bool CanEdit
{
    get { return WS.SessionProfile.SuperAdmin || HasUserGrant(20200); }
}

CompilationController.cs:19-22 (controller → BL via proxy):

public int Save_XML(Guid provUserKey, int idEntity, string entity, string xml, string note)
{
    return ((ICompilationBL)base.DAO).Save_XML(provUserKey, idEntity, entity, xml, note);
}

DAOFactory.cs:26-27 (confine .NET Remoting):

case enControllers.Ctrl_Compilation:
    return (IBase_BL)Activator.GetObject(typeof(ICompilationBL), SettingsManager.CHANNEL + "://" + SettingsManager.SERVERADDRESS + "/" + Properties.CensusDictionary.Service_Compilation);

CompilationBL.cs:13-16 (BL → DAL):

public int Save_XML(Guid provUserKey, int idEntity, string entity, string xml, string note)
{
    return Census.CensusDAL.CensusDALFactory.GetCompilationDAL().Save_XML(provUserKey, idEntity, entity, xml, note);
}

CompilationDAL.cs:22-46 (parametri + chiamata SP + id di ritorno):

public int Save_XML(Guid provUserKey, int idEntity, string entity, string xml, string note)
{
    OracleParameter idUserParam   = new OracleParameter("PIDUSER", OracleDbType.Raw, provUserKey, ParameterDirection.Input);
    OracleParameter idEntityParam = new OracleParameter("PIDENTITY", OracleDbType.Int32, idEntity, ParameterDirection.Input);
    OracleParameter entityParam   = new OracleParameter("PENTITY", OracleDbType.Varchar2, entity, ParameterDirection.Input);
    OracleParameter xmlParam      = new OracleParameter("PXML", OracleDbType.XmlType, xml, ParameterDirection.Input);
    OracleParameter noteParam     = new OracleParameter("PNOTE", OracleDbType.Varchar2, note, ParameterDirection.Input);
    OracleParameter outparam      = new OracleParameter("PIDCOMPILATION", OracleDbType.Int32, ParameterDirection.Output);
    using (DataLayer dl = new DataLayer(ConnectionName))
    {
        dl.Parameters.Add(idUserParam); ... dl.Parameters.Add(outparam);
        if (dl.ExecuteNonQueryStoredProcedure("CNS_NEWCOMPILATION_XML"))
            return ((Oracle.DataAccess.Types.OracleDecimal)outparam.Value).ToInt32();
        else return -1;
    }
}

Sorgente DB (Oracle INFOCAD_TEST38, via USER_SOURCE / USER_TAB_COLUMNS — read-only bounded)

CNS_NEWCOMPILATION_XML (USER_SOURCE, 13 righe):

PROCEDURE "CNS_NEWCOMPILATION_XML" (PIDUSER        IN  RAW,
                                    PIDENTITY      IN  NUMBER,
                                    PENTITY        IN  VARCHAR2,
                                    PXML           IN  XMLTYPE,
                                    PNOTE          IN  VARCHAR2,
                                    PIDCOMPILATION OUT NUMBER)
AS
BEGIN
  INSERT INTO CENSUS_XML (
    IDENTITY, ENTITY, IDUSER, COMPILATION_DATE, XML, DESCRIPTION
  )
  VALUES (PIDENTITY, PENTITY, PIDUSER, SYSDATE, PXML, PNOTE) RETURNING ID INTO PIDCOMPILATION;
END;

CENSUS_XML (USER_TAB_COLUMNS):

ID               NUMBER      NOT NULL
IDENTITY         NUMBER      NOT NULL
ENTITY           VARCHAR2    NOT NULL
IDUSER           RAW         NOT NULL
COMPILATION_DATE DATE        NOT NULL
XML              XMLTYPE     NULL
DESCRIPTION      VARCHAR2    NULL
ISCANCELLED      NUMBER      NOT NULL DEFAULT 0

CNS_UPDATECOMPILATION_XML (USER_SOURCE, path alternativo — update condizionale per campo):

PROCEDURE "CNS_UPDATECOMPILATION_XML" (PID IN NUMBER, PIDUSER IN RAW, PIDENTITY IN NUMBER,
                                       PENTITY IN VARCHAR2, PXML IN XMLTYPE, PNOTE IN VARCHAR2)
AS BEGIN
  IF PIDUSER   IS NOT NULL THEN UPDATE CENSUS_XML SET IDUSER=PIDUSER WHERE ID=PID; END IF;
  IF PIDENTITY > 0         THEN UPDATE CENSUS_XML SET IDENTITY=PIDENTITY WHERE ID=PID; END IF;
  IF PENTITY   IS NOT NULL THEN UPDATE CENSUS_XML SET ENTITY=PENTITY WHERE ID=PID; END IF;
  IF PXML      IS NOT NULL THEN UPDATE CENSUS_XML SET XML=PXML, COMPILATION_DATE=SYSDATE WHERE ID=PID; END IF;
  IF PNOTE     IS NOT NULL THEN UPDATE CENSUS_XML SET DESCRIPTION=PNOTE WHERE ID=PID; END IF;
END;

Confidence

VERIFIED. Due tipi di evidenza indipendenti e concordanti:

  1. Codice applicativo (C#): catena completa UI → Controller → (Remoting) → BL → DAL con nome stored procedure e parametri.
  2. Sorgente/schema DB Oracle (USER_SOURCE, USER_TAB_COLUMNS): corpo della procedura CNS_NEWCOMPILATION_XML che esegue l'INSERT su CENSUS_XML, e struttura della tabella.

Forward (UI→DB) e reverse (SP→tabella→parametri DAL) concordano: i 6 parametri del DAL (PIDUSER/PIDENTITY/PENTITY/PXML/PNOTE/PIDCOMPILATION) corrispondono 1:1 alla firma della procedura, e le colonne inserite corrispondono allo schema di CENSUS_XML.

Open questions

  • Configurazione runtime del canale .NET Remoting (SettingsManager.CHANNEL/SERVERADDRESS) e nome effettivo del servizio Service_Compilation: non risolti a runtime (valori da config del server).
  • Semantica dei valori possibili di ENTITY oltre a EDIFICIO/PIANO/UI e uso a valle dell'XML (mapping linkedToField/linkedToTable) — fuori dallo scope del solo WRITE.
  • ISCANCELLED non è toccato dalla INSERT/UPDATE: la cancellazione (CNS_DELETECOMPILATION_XML) non è stata ispezionata per confermare se sia logica (flag) o fisica.