Passa al contenuto principale

Tutorial — aggiungere un campo a reg.companies

Esempio reg-specifico del pattern generale di estensione CRUD. Per i passi generali del generatore (sync DB, invocazione MCP, rigenerazione, commit), vedi il tutorial base nel dominio inv: Aggiungere un campo su inv.invoices.

Questa pagina mostra solo le specificità applicabili a reg.companies.

🎯 Cosa fa

Tutorial sull'aggiunta di un campo noteInterne (note riservate al personale amministrativo, non visibili al cliente) alla tabella reg.companies. Copre le particolarità di un'entità con AddressFormatter, cascade ATECO e hook QueryModifier.

⚠️ Prerequisiti

Stessi del tutorial inv:

  • Ambiente sviluppo con TrainingHub.Database apribile
  • DB locale collegato
  • MCP 3sd-generator configurato
  • Branch dedicato

👣 Passi

1. Modifica reg.companies nel progetto DB

File: TrainingHub.Database/reg/Tables/companies.sql.

Aggiungi la colonna dopo le altre colonne testo e gli extended properties corrispondenti:

CREATE TABLE [reg].[companies] (
[id] UNIQUEIDENTIFIER CONSTRAINT [DEFAULT_companies_id] DEFAULT (newid()) NOT NULL,
-- ... righe esistenti ...
[notes] NVARCHAR (1024) NULL,
[noteInterne] NVARCHAR (MAX) NULL,
-- ... righe esistenti + constraint ...
);

GO
EXECUTE sp_addextendedproperty @name = N'MS_Description',
@value = N'Note interne riservate al personale amministrativo (non visibili al cliente)',
@level0type = N'SCHEMA', @level0name = N'reg',
@level1type = N'TABLE', @level1name = N'companies',
@level2type = N'COLUMN', @level2name = N'noteInterne';
GO

Note reg-specifiche:

  • NVARCHAR(MAX) per contenuto lungo. Non appesantisce la riga a meno che non sia popolato (SQL Server tiene MAX off-row se serve).
  • Evita di piazzare il campo fra le colonne indirizzo: l'AddressFormatter del form si aspetta un layout contiguo di campi indirizzo.

2. Sincronizza il DB locale

Uguale al tutorial inv: sqlpackage /Action:Publish o Visual Studio Publish.

3. Verifica conf.json

File: TrainingHub.BackOffice/Components/CRUD/reg/_conf/companies.dxgrid.conf.json.

Per default il generatore include il nuovo campo in grid e form. Per noteInterne probabilmente vuoi:

  • Nascondere in grid di default (testo lungo, ingombrante in lista)
  • Mostrare in form (editabile)
  • Posizionare nella sezione delle note esistenti nel FormOrder
{
"Columns": {
"noteInterne": {
"Visible": false,
"FormInsertVisibility": "editable",
"FormUpdateVisibility": "editable"
}
},
"FormOrder": [
// ... altri campi ...
"notes",
"noteInterne"
]
}

4. Esegui rigenerazione CRUD

Invoca il tool MCP:

  • mcp__3sd-generator__generator_run per l'entità companies

File che devono cambiare:

TrainingHub.BackOffice/Components/CRUD/reg/Company.razor
TrainingHub.BackOffice/Components/CRUD/reg/Company.razor.tt.cs
TrainingHub.BackOffice/Components/CRUD/reg/Forms/CompanyForm.razor
TrainingHub.BackOffice/Components/CRUD/reg/Forms/CompanyForm.razor.tt.cs

File che non devono cambiare:

Company.razor.cs (code-behind custom con servizi inject)
Forms/CompanyForm.razor.cs (SetRiskLevelId, ValidateVatCodeAsync)

5. (Se serve) gestione cross-dominio

Se il nuovo campo deve essere letto da altri domini (es. noteInterne mostrate nel modulo di fatturazione):

  1. Rigenera anche il DataLayer se necessario.
  2. Aggiungi accessor nei code-behind che ne hanno bisogno.
  3. Attenzione: campi visibili solo ad admin vanno protetti con policy di autorizzazione se esposti in altre sezioni.

6. Test cascade e QueryModifier

Modifiche a companies attivano automaticamente CompaniesQueryModifier.PostExecutionQuery che ricalcola il rischio dei workers. Per il nuovo campo noteInterne non è desiderato: la modifica di note non dovrebbe triggerare cascade rischio (che però lo fa comunque, perché il modifier non discrimina per campo).

Valutazione: accettabile come side-effect (costo medio-basso) o refactoring per discriminare per campo modificato (costo alto, richiede confronto entity pre/post).

7. Build, test, commit

dotnet build TrainingHub.sln
dotnet test TrainingHub.Tests

git add TrainingHub.Database/reg/Tables/companies.sql
git commit -m "feat(db): add noteInterne to reg.companies"

git add TrainingHub.BackOffice/Components/CRUD/reg/_conf/companies.dxgrid.conf.json
git commit -m "feat(reg): show noteInterne in company form"

git add TrainingHub.BackOffice/Components/CRUD/reg/Company.razor \
TrainingHub.BackOffice/Components/CRUD/reg/Company.razor.tt.cs \
TrainingHub.BackOffice/Components/CRUD/reg/Forms/CompanyForm.razor \
TrainingHub.BackOffice/Components/CRUD/reg/Forms/CompanyForm.razor.tt.cs
git commit -m "regen reg.companies"

⚡ Casi particolari reg

  • Campo indirizzo nuovo. Se il campo fa parte dello schema AddressFormatter (country, province, city, zipCode, address, streetNumber, formattedAddress, latitude, longitude), il componente lo gestisce automaticamente; non serve markup custom.
  • Campo FK verso altra tabella reg. Il generatore crea automaticamente un EditComboBox con autorizzazione page-<scheme>-<table> e popup di edit inline. Se la tabella referenziata è fuori scope (es. companySubcategories), verifica che esista anche il suo CRUD generato.
  • Campo trigger cascade rischio. Oggi CompaniesQueryModifier ricalcola il rischio a ogni Update. Se il tuo campo NON dovrebbe triggerare cascade (es. noteInterne), documenta la scelta ma accetta il costo fino a refactoring del modifier.
  • Campo con validazione formato. La validazione P.IVA/CF/SDI oggi non è strutturata; se aggiungi un campo che richiede validazione (es. un nuovo codice fiscale), implementa la logica in CompanyForm.razor.cs o aspetta un service dedicato futuro.

⚠️ Domande aperte

  • Discriminazione cascade rischio per campo. Il QueryModifier ricalcola workers su ogni update company. Per nuovi campi "non rischiosi" (note, logo, ecc.) è overhead. Valutare confronto old vs new entity per triggerare solo su cambi reali ad atecoCode o riskLevelId.
  • Sensibilità dei nuovi campi. Campi come noteInterne non devono essere esposti in API o UI cliente. Serve un'annotazione o convention di progetto per marcarli.

🔗 Vedi anche