Tutorial — aggiungere un campo a una fattura
Guida end-to-end per aggiungere un nuovo campo a una tabella inv e
propagarlo automaticamente fino alla UI. L'esempio aggiunge il campo
customerPurchaseOrder (riferimento ordine cliente) alla tabella
inv.invoices.
🎯 Cosa fa
Il tutorial copre il flusso completo:
- Modifica schema DB (file SQL)
- Sincronizzazione DB locale
- Rigenerazione CRUD (tabella + grid + form)
- Ritocchi su
conf.jsonper visibilità e posizione - Eventuale logica custom nel code-behind
- Verifica finale
⚠️ Prerequisiti
- Ambiente di sviluppo con
TrainingHub.Databaseapribile in Visual Studio / SSDT. - Database locale collegato alla BackOffice.
- Accesso al server MCP
3sd-generatorconfigurato in Claude Code (vedi.claude/settings.json). - Branch feature dedicato (no modifiche dirette su
master/continuous-integration).
👣 Passi
1. Modifica inv.invoices nel progetto DB
File: TrainingHub.Database/inv/Tables/invoices.sql.
Aggiungi la colonna all'interno della CREATE TABLE e gli extended
properties corrispondenti:
CREATE TABLE [inv].[invoices] (
[id] UNIQUEIDENTIFIER CONSTRAINT [DEFAULT_invoices_id] DEFAULT (newid()) NOT NULL,
-- ... (righe esistenti) ...
[customerPurchaseOrder] NVARCHAR (64) NULL,
[createdAt] DATETIME CONSTRAINT [DEFAULT_invoices_createdAt] DEFAULT (getdate()) NOT NULL,
[updatedAt] DATETIME NULL,
-- ... (constraints esistenti) ...
);
GO
EXECUTE sp_addextendedproperty @name = N'MS_Description',
@value = N'riferimento ordine cliente (opzionale)',
@level0type = N'SCHEMA', @level0name = N'inv',
@level1type = N'TABLE', @level1name = N'invoices',
@level2type = N'COLUMN', @level2name = N'customerPurchaseOrder';
GO
Salva e fai build del progetto TrainingHub.Database per verificare
che il .sqlproj compili.
2. Sincronizza il DB locale
Regola di progetto: prima di rigenerare i CRUD, la modifica DB deve essere già applicata allo schema locale (il generatore legge dallo schema vivo, non dai file
.sql).
Opzioni per sincronizzare:
- Publish DACPAC via Visual Studio —
TrainingHub.Database→ Publish → scegli connection string dev → Publish. sqlpackage.exeda riga di comando:sqlpackage /Action:Publish \/SourceFile:"TrainingHub.Database/bin/Debug/TrainingHub.Database.dacpac" \/TargetConnectionString:"Server=...;Database=TrainingHub_Dev;Integrated Security=true;TrustServerCertificate=true"- Script manuale — estrai lo
ALTER TABLEdal diff DACPAC e applicalo a mano (sconsigliato in dev).
Dopo l'apply, connetti SSMS al DB e verifica che inv.invoices abbia la
nuova colonna.
3. Esegui la rigenerazione CRUD
Nel file di configurazione conf.json il campo viene incluso
automaticamente se non è esplicitamente filtrato. Invoca il tool MCP
3sd-generator da Claude Code:
mcp__3sd-generator__generator_list_settings— elenca le configurazioni disponibilimcp__3sd-generator__generator_run— esegui perinv.invoices
Dopo la rigenerazione controlla con git status: devono essere
modificati i file auto-generati per Invoice:
modified: TrainingHub.BackOffice/Components/CRUD/inv/Invoice.razor
modified: TrainingHub.BackOffice/Components/CRUD/inv/Invoice.razor.tt.cs
modified: TrainingHub.BackOffice/Components/CRUD/inv/Forms/InvoiceForm.razor
modified: TrainingHub.BackOffice/Components/CRUD/inv/Forms/InvoiceForm.razor.tt.cs
I file *.razor.cs (code-behind custom) non devono cambiare.
4. Ritocca conf.json per visibilità / posizione
File: TrainingHub.BackOffice/Components/CRUD/inv/_conf/invoices.dxgrid.conf.json.
Tipicamente vuoi controllare:
- Visibilità in grid — sezione
Columns, proprietàVisible - Visibilità in form per insert/update — sezione
Columns, proprietàFormInsertVisibility/FormUpdateVisibility(valori:editable|readonly|hidden) - Ordine in form — aggiungi il nome campo all'array
FormOrdernel punto desiderato
Esempio: voglio il campo visibile in grid come colonna opzionale (nascosta di default) e editabile in form sempre:
{
"Columns": {
"customerPurchaseOrder": {
"Visible": false,
"FormInsertVisibility": "editable",
"FormUpdateVisibility": "editable"
}
},
"FormOrder": [
"issuerId",
"companyId",
"issueDate",
"customerPurchaseOrder",
"notes"
]
}
Dopo la modifica ri-esegui generator_run per applicare il nuovo
posizionamento.
5. (Opzionale) logica custom nel code-behind
Se il nuovo campo richiede logica non generabile (es. validazione custom, pre-popolamento, lookup da altra entità), aggiungi il codice in:
Invoice.razor.csper handler a livello gridForms/InvoiceForm.razor.csper logica a livello form
Esempio di pre-popolamento al caricamento form:
// Forms/InvoiceForm.razor.cs (partial class)
public partial class InvoiceForm
{
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
if (isEditingNewRow && string.IsNullOrEmpty(dataItem.customerPurchaseOrder))
{
dataItem.customerPurchaseOrder = await GetNextOrderRefAsync();
}
}
}
6. Aggiorna XML FatturaPA (se il campo va inviato al SDI)
Se il campo deve comparire nell'XML trasmesso al SDI:
- Modifica
IFatturaPaXmlGenerator.Generateper includere il tag appropriato (es.<DatiOrdineAcquisto>per i riferimenti ordine). - Aggiungi test in
TrainingHub.Tests/Services/Invoicing/FatturaPaXmlGeneratorTests.cs. - Valida l'XML contro lo schema XSD FatturaPA 1.2.
7. Build e test
dotnet build TrainingHub.sln
dotnet test TrainingHub.Tests
Avvia la BackOffice e verifica manualmente:
- Il campo è presente nel form di nuova fattura
- Il valore viene salvato / riletto correttamente
- Il wizard non è rotto (tutti i 5 step funzionano)
- Se editato nell'XML: il file generato contiene il nuovo tag
8. Commit
Convenzione di progetto: commit separati per DB e rigenerazione.
# Commit 1 — schema DB
git add TrainingHub.Database/inv/Tables/invoices.sql
git commit -m "feat(db): add customerPurchaseOrder to inv.invoices"
# Commit 2 — conf.json
git add TrainingHub.BackOffice/Components/CRUD/inv/_conf/invoices.dxgrid.conf.json
git commit -m "feat(inv): show customerPurchaseOrder in invoice form"
# Commit 3 — regen
git add TrainingHub.BackOffice/Components/CRUD/inv/Invoice.razor \
TrainingHub.BackOffice/Components/CRUD/inv/Invoice.razor.tt.cs \
TrainingHub.BackOffice/Components/CRUD/inv/Forms/InvoiceForm.razor \
TrainingHub.BackOffice/Components/CRUD/inv/Forms/InvoiceForm.razor.tt.cs
git commit -m "regen inv.invoices"
# (Eventuale) Commit 4 — code-behind custom / XML generator
git add TrainingHub.BackOffice/Components/CRUD/inv/Forms/InvoiceForm.razor.cs
git commit -m "feat(inv): prefill customerPurchaseOrder on new invoice"
Commit piccoli e specifici facilitano review e rollback.
⚡ Casi particolari
- Campo NOT NULL senza default. Alla publish del DACPAC SQL Server
lancia errore se la tabella ha già righe. Aggiungi un
DEFAULT ('...')o marca comeNULLin prima battuta, poi stringi in una migration successiva. - FK su tabella di altro schema. Aggiungi il FK constraint nello
stesso
CREATE TABLE(oALTERvia post-deploy script). Assicurati che la tabella referenziata sia in una referenze project (reg,edu, ecc.) collegata al.sqlproj. - Rinominare un campo esistente. Non supportato direttamente. Crea il nuovo campo, migra i dati via post-deploy script, poi in un commit successivo rimuovi il vecchio campo. Due step per evitare perdita dati.
- Campi con encoding particolare (JSON, XML). Usa
NVARCHAR(MAX)e gestisci serializzazione lato C# (il generatore non crea validatori custom). - Effetti sul wizard fattura. Se il campo va nello step 1 del
wizard, può richiedere aggiornamenti in
InvoiceFormPopup.razor.cs/SaveInvoiceDraftse deve essere validato o inizializzato.
⚠️ Domande aperte
- Script di sync DB automatizzato. Oggi la sincronizzazione DB
pre-regen è manuale. Valutare script npm / PowerShell che incapsuli
sqlpackage /Action:Publishcon connection string daappsettings.Development.json. - Verifica post-regen automatica. Dopo
generator_runnon c'è un check automatico che tutti i file attesi siano stati aggiornati. Valutare un assert in CI che confrontigit diff --statcon un elenco atteso. - Rollback rigenerazione. Se la regen sbaglia (es. config
errata),
git checkout <files>ripristina ma i file.razor.cscustom vanno conservati. Documentare procedura di rollback pulita.
🔗 Vedi anche
- Panoramica dominio — mappa del dominio
- Schema DB — tabelle e relazioni
- Componenti UI — pattern CRUD e triade file
- Servizi — logica InvoiceService e XML FatturaPA
CLAUDE.md(root repo) — regole di generazione CRUD e progetto DB