Passa al contenuto principale

Tutorial — aggiungere un campo a job.workers

Esempio job-specifico del pattern di estensione CRUD. Per i passi comuni (sync DB, MCP generator, rigenerazione) vedi Aggiungere un campo su inv.invoices.

Questa pagina mostra le specificità del dominio job.

🎯 Cosa fa

Esempio: aggiungere un campo emergencyContactPhone (numero di un familiare o amico contattabile in emergenza) alla tabella job.workers.

⚠️ Prerequisiti

Stessi del tutorial generale: ambiente sviluppo + DB locale + MCP generator + branch dedicato.

👣 Passi

1. Modifica job.workers

File: TrainingHub.Database/job/Tables/workers.sql

Aggiungi il campo accanto a phone:

CREATE TABLE [job].[workers] (
-- ... campi esistenti ...
[phone] NVARCHAR (1024) NULL,
[emergencyContactPhone] NVARCHAR (128) NULL,
-- ... altri campi ...
);

GO
EXECUTE sp_addextendedproperty @name = N'MS_Description',
@value = N'Numero telefonico da contattare in caso di emergenza',
@level0type = N'SCHEMA', @level0name = N'job',
@level1type = N'TABLE', @level1name = N'workers',
@level2type = N'COLUMN', @level2name = N'emergencyContactPhone';
GO

Considerazioni job-specifiche:

  • Non toccare i campi chiave del cascade: companyId, companyLocationId, roleId, riskLevelId, departmentId, academicQualificationId. Modifiche a questi triggerano cascade QueryModifier.
  • Non interferire con la computed column label (derivata da firstName + lastName).
  • Indici: il nuovo campo non deve pesare sugli indici filtered esistenti (IX_workers_fiscalCode, IX_workers_active). Se il campo diventa frequentemente filtrato, valutare aggiunta indice dedicato.

2. Sincronizza il DB

Come altri tutorial.

3. conf.json — considerazioni job

File: TrainingHub.BackOffice/Components/CRUD/job/_conf/workers.dxgrid.conf.json

Per un campo contatto opzionale:

{
"Columns": {
"emergencyContactPhone": {
"Visible": false,
"FormInsertVisibility": "editable",
"FormUpdateVisibility": "editable"
}
},
"FormOrder": [
// ... altri campi ...
"phone",
"emergencyContactPhone",
// ...
]
}

Nascondi in grid di default (campi contatto spesso ingombranti) ma lascia editabile nel form.

4. Rigenera

Invoca mcp__3sd-generator__generator_run per workers. File rigenerati:

TrainingHub.BackOffice/Components/CRUD/job/Worker.razor
TrainingHub.BackOffice/Components/CRUD/job/Worker.razor.tt.cs
TrainingHub.BackOffice/Components/CRUD/job/Forms/WorkerForm.razor
TrainingHub.BackOffice/Components/CRUD/job/Forms/WorkerForm.razor.tt.cs

Non devono cambiare:

  • Worker.razor.cs — code-behind custom con cascade FK filter
  • Forms/WorkerForm.razor.cs — auto-calcolo da CF
  • WorkerEffectiveRisk.razor — vista rischi
  • WorkersData.razor — vista analitica
  • WorkerJobHistory.razor — storico (non include i nuovi campi)

5. Aggiorna viste analitiche (se rilevante)

Se il campo va incluso in WorkersData.razor (vista aggregata), va aggiornato a mano: non è CRUD generato.

Per emergencyContactPhone non è rilevante (dato individuale), ma lo sarebbe per campi aggregabili (es. anniDiServizio).

6. Considera impatto su cascade rischi

Per un campo puramente informativo come emergencyContactPhone:

  • Non triggera cascade.
  • Il CompaniesQueryModifier (reg) continuerà a chiamare worker.UpdateRiskLevel al cambio azienda, anche se il nuovo campo non è coinvolto — inefficiente ma inevitabile senza discriminazione per campo modificato (debito noto).

Per un campo che invece influenza il cascade (es. un nuovo riskFactorId):

  • Aggiornare IRiskInheritanceService per tenerne conto.
  • Aggiungere QueryModifier dedicato se serve hook su cambi.
  • Ricalcolare workers.riskLevelId materializzato.

7. Considera impatto su workerJobHistory

Se il campo deve essere storicizzato (es. un dato che cambia nel tempo e serve audit):

  • Aggiungi il campo anche a workerJobHistory con lo stesso tipo.
  • Aggiorna la logica di snapshot che popola workerJobHistory al cambio mansione per copiare anche il nuovo campo.

Per emergencyContactPhone non serve.

8. Considera impatto su import Excel

TrainingHub.Import importa anche workers. Il nuovo campo:

  • Non viene popolato automaticamente — l'Excel deve avere la colonna e il mapping va aggiornato.
  • Campi ottimali nullable (come questo) non rompono l'import esistente.

9. Build, test, commit

dotnet build TrainingHub.sln
dotnet test TrainingHub.Tests

git add TrainingHub.Database/job/Tables/workers.sql
git commit -m "feat(db): add emergencyContactPhone to job.workers"

git add TrainingHub.BackOffice/Components/CRUD/job/_conf/workers.dxgrid.conf.json
git commit -m "feat(job): show emergencyContactPhone in worker form"

git add TrainingHub.BackOffice/Components/CRUD/job/Worker.razor \
TrainingHub.BackOffice/Components/CRUD/job/Worker.razor.tt.cs \
TrainingHub.BackOffice/Components/CRUD/job/Forms/WorkerForm.razor \
TrainingHub.BackOffice/Components/CRUD/job/Forms/WorkerForm.razor.tt.cs
git commit -m "regen job.workers"

⚡ Casi particolari job

  • Nuovo campo cascade-sensitive. Se il campo ha impatto su riskLevelId del lavoratore (tipicamente improbabile — il cascade gira su rischi e ATECO, non su campi worker), aggiorna RiskInheritanceService e valida ricalcolo.
  • Nuovo campo su jobs (mansione). Se tocca riskLevelId o inheritsCompanyRisks, servirà un refresh massivo di workers.riskLevelId: costoso su dataset grandi.
  • Nuovo rischio. Aggiungere una voce a risks è banale (label + id). Impatta i flussi di assegnazione e può richiedere aggiornamento di eventuali viste pre-calcolate su compliance.
  • Nuovo codice ATECO. ATECO ha parentCode (gerarchia) + flag selectable: inserire come figlio di un codice esistente e impostare selectable coerentemente.
  • Nuovo livello di rischio. riskLevel.id è INT. Aggiungere un 4° livello (es. "Critico"): potrebbe richiedere aggiornamenti a tabelle con riskLevelId nullable (oggi interpretato come "eredita parent") e a UI che mostrano livelli.

⚠️ Domande aperte

  • Impatto su import Excel. Il mapping TrainingHub.Import va aggiornato manualmente. Checklist dei mapping da toccare per ogni tabella modificata.
  • Discriminazione cascade per campo. Problema ricorrente (già in reg): modificare un campo non cascade-sensitive (es. note) triggera comunque refresh globale di workers.riskLevelId. Ottimizzazione futura.
  • workerJobHistory sincronizzato automaticamente. Se aggiungi un campo storicizzabile a workers, la logica di snapshot va aggiornata in più punti (form custom, hook DB, trigger). Manca pattern centralizzato.

🔗 Vedi anche