@chill-sharp/ui-core 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/chillsharp-current-user-preferences/SKILL.md +70 -0
- package/.agents/skills/chillsharp-ui-template/SKILL.md +18 -0
- package/README.md +103 -0
- package/chill-sharp-ui-core.d.ts.map +1 -0
- package/doc/AIAssistedDevelopment/README.md +185 -0
- package/doc/AttachmentModel/README.md +173 -0
- package/doc/AuthenticationModel/README.md +213 -0
- package/doc/AuthenticationModel/how-to-integreate-auth-minimal-api.md +293 -0
- package/doc/ChillSharpClient.md +464 -0
- package/doc/ClientGeneration/README.md +172 -0
- package/doc/ComplianceGuide/README.md +178 -0
- package/doc/Configuration/README.md +94 -0
- package/doc/CurrentUserPreferences.md +114 -0
- package/doc/DateTimePolicy/README.md +154 -0
- package/doc/DateTimeSerialization.md +423 -0
- package/doc/Endpoints.md +260 -0
- package/doc/HowTo/01-simple-blog-sqlite.md +153 -0
- package/doc/HowTo/02-blog-schema-labels.md +140 -0
- package/doc/HowTo/03-authentication.md +218 -0
- package/doc/HowTo/04-blog-posts-one-to-many.md +194 -0
- package/doc/HowTo/05-docker-env-variables.md +274 -0
- package/doc/HowTo/06-chunk-transactions-autocomplete.md +196 -0
- package/doc/Mcp/ChatGPT.md +291 -0
- package/doc/Mcp/README.md +799 -0
- package/doc/MenuGuide/README.md +49 -0
- package/doc/ModelPreparation.md +255 -0
- package/doc/PermissionModel/README.md +277 -0
- package/doc/README.md +228 -0
- package/doc/ReferenceExistence.md +130 -0
- package/doc/RegisterContext.md +217 -0
- package/doc/UiCore/CRUD.md +170 -0
- package/doc/UiCore/README.md +13 -0
- package/doc/ValidationModel/README.md +117 -0
- package/doc/it/AIAssistedDevelopment/README.md +185 -0
- package/doc/it/AttachmentModel/README.md +173 -0
- package/doc/it/AuthenticationModel/README.md +171 -0
- package/doc/it/AuthenticationModel/how-to-integreate-auth-minimal-api.md +292 -0
- package/doc/it/ChillSharpClient.md +464 -0
- package/doc/it/ClientGeneration/README.md +152 -0
- package/doc/it/ComplianceGuide/README.md +178 -0
- package/doc/it/Configuration/README.md +94 -0
- package/doc/it/CurrentUserPreferences.md +114 -0
- package/doc/it/DateTimePolicy/README.md +154 -0
- package/doc/it/DateTimeSerialization.md +423 -0
- package/doc/it/Endpoints.md +260 -0
- package/doc/it/HowTo/01-simple-blog-sqlite.md +152 -0
- package/doc/it/HowTo/02-blog-schema-labels.md +139 -0
- package/doc/it/HowTo/03-authentication.md +221 -0
- package/doc/it/HowTo/04-blog-posts-one-to-many.md +193 -0
- package/doc/it/HowTo/05-docker-env-variables.md +268 -0
- package/doc/it/HowTo/06-chunk-transactions-autocomplete.md +196 -0
- package/doc/it/Mcp/ChatGPT.md +291 -0
- package/doc/it/Mcp/README.md +799 -0
- package/doc/it/MenuGuide/README.md +49 -0
- package/doc/it/ModelPreparation.md +254 -0
- package/doc/it/PermissionModel/README.md +190 -0
- package/doc/it/README.md +172 -0
- package/doc/it/ReferenceExistence.md +130 -0
- package/doc/it/RegisterContext.md +218 -0
- package/doc/it/UiCore/CRUD.md +170 -0
- package/doc/it/UiCore/README.md +13 -0
- package/doc/it/ValidationModel/README.md +117 -0
- package/fesm2022/chill-sharp-ui-core.mjs +16725 -0
- package/fesm2022/chill-sharp-ui-core.mjs.map +1 -0
- package/index.d.ts +6 -0
- package/lib/chill-sharp-ui-root.component.d.ts +6 -0
- package/lib/chill-sharp-ui-root.component.d.ts.map +1 -0
- package/lib/chill-sharp-ui.routes.d.ts +3 -0
- package/lib/chill-sharp-ui.routes.d.ts.map +1 -0
- package/lib/chill.config.d.ts +5 -0
- package/lib/chill.config.d.ts.map +1 -0
- package/lib/layouts/auth-shell.component.d.ts +8 -0
- package/lib/layouts/auth-shell.component.d.ts.map +1 -0
- package/lib/layouts/workspace-page.component.d.ts +49 -0
- package/lib/layouts/workspace-page.component.d.ts.map +1 -0
- package/lib/lib/chill-form.component.d.ts +151 -0
- package/lib/lib/chill-form.component.d.ts.map +1 -0
- package/lib/lib/chill-i18n-button-label.component.d.ts +27 -0
- package/lib/lib/chill-i18n-button-label.component.d.ts.map +1 -0
- package/lib/lib/chill-i18n-label.component.d.ts +30 -0
- package/lib/lib/chill-i18n-label.component.d.ts.map +1 -0
- package/lib/lib/chill-json-input.component.d.ts +31 -0
- package/lib/lib/chill-json-input.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-boolean-control.component.d.ts +12 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-boolean-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-editor-control.component.d.ts +17 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-editor-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-lookup-control.component.d.ts +45 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-lookup-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-scalar-control.component.d.ts +19 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-scalar-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-select-control.component.d.ts +12 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-select-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-textarea-control.component.d.ts +13 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-textarea-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input.component.d.ts +452 -0
- package/lib/lib/chill-polymorphic-input.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-boolean-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-boolean-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-lookup-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-lookup-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-number-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-number-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-temporal-control.component.d.ts +8 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-temporal-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-value-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-value-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output.component.d.ts +75 -0
- package/lib/lib/chill-polymorphic-output.component.d.ts.map +1 -0
- package/lib/lib/chill-table.component.d.ts +434 -0
- package/lib/lib/chill-table.component.d.ts.map +1 -0
- package/lib/lib/chill-text-editor-dialog.component.d.ts +14 -0
- package/lib/lib/chill-text-editor-dialog.component.d.ts.map +1 -0
- package/lib/lib/crud-configuration.utils.d.ts +4 -0
- package/lib/lib/crud-configuration.utils.d.ts.map +1 -0
- package/lib/lib/culture-name-options.d.ts +3 -0
- package/lib/lib/culture-name-options.d.ts.map +1 -0
- package/lib/lib/date-format-options.d.ts +3 -0
- package/lib/lib/date-format-options.d.ts.map +1 -0
- package/lib/lib/iana-time-zone-options.d.ts +3 -0
- package/lib/lib/iana-time-zone-options.d.ts.map +1 -0
- package/lib/lib/notice-transition.directive.d.ts +17 -0
- package/lib/lib/notice-transition.directive.d.ts.map +1 -0
- package/lib/lib/schema-property-dialog.component.d.ts +74 -0
- package/lib/lib/schema-property-dialog.component.d.ts.map +1 -0
- package/lib/models/chill-auth.models.d.ts +176 -0
- package/lib/models/chill-auth.models.d.ts.map +1 -0
- package/lib/models/chill-menu.models.d.ts +12 -0
- package/lib/models/chill-menu.models.d.ts.map +1 -0
- package/lib/models/chill-schema.models.d.ts +141 -0
- package/lib/models/chill-schema.models.d.ts.map +1 -0
- package/lib/models/workspace-dialog.models.d.ts +16 -0
- package/lib/models/workspace-dialog.models.d.ts.map +1 -0
- package/lib/models/workspace-task.models.d.ts +36 -0
- package/lib/models/workspace-task.models.d.ts.map +1 -0
- package/lib/pages/confirm-reset-page.component.d.ts +21 -0
- package/lib/pages/confirm-reset-page.component.d.ts.map +1 -0
- package/lib/pages/crud/attachment-upload-dialog.component.d.ts +24 -0
- package/lib/pages/crud/attachment-upload-dialog.component.d.ts.map +1 -0
- package/lib/pages/crud/crud-page.component.d.ts +244 -0
- package/lib/pages/crud/crud-page.component.d.ts.map +1 -0
- package/lib/pages/login-page.component.d.ts +21 -0
- package/lib/pages/login-page.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-role-dialog.component.d.ts +29 -0
- package/lib/pages/permissions/auth-role-dialog.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-search-select.component.d.ts +28 -0
- package/lib/pages/permissions/auth-search-select.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-user-dialog.component.d.ts +35 -0
- package/lib/pages/permissions/auth-user-dialog.component.d.ts.map +1 -0
- package/lib/pages/permissions/permission-editor.component.d.ts +55 -0
- package/lib/pages/permissions/permission-editor.component.d.ts.map +1 -0
- package/lib/pages/permissions/permissions-page.component.d.ts +38 -0
- package/lib/pages/permissions/permissions-page.component.d.ts.map +1 -0
- package/lib/pages/permissions/role-permission.component.d.ts +43 -0
- package/lib/pages/permissions/role-permission.component.d.ts.map +1 -0
- package/lib/pages/permissions/user-permission.component.d.ts +43 -0
- package/lib/pages/permissions/user-permission.component.d.ts.map +1 -0
- package/lib/pages/register-page.component.d.ts +24 -0
- package/lib/pages/register-page.component.d.ts.map +1 -0
- package/lib/pages/reset-password-page.component.d.ts +18 -0
- package/lib/pages/reset-password-page.component.d.ts.map +1 -0
- package/lib/provide-chill-sharp-ui-core.d.ts +8 -0
- package/lib/provide-chill-sharp-ui-core.d.ts.map +1 -0
- package/lib/services/chill.service.d.ts +249 -0
- package/lib/services/chill.service.d.ts.map +1 -0
- package/lib/services/workspace-dialog.service.d.ts +22 -0
- package/lib/services/workspace-dialog.service.d.ts.map +1 -0
- package/lib/services/workspace-layout.service.d.ts +13 -0
- package/lib/services/workspace-layout.service.d.ts.map +1 -0
- package/lib/services/workspace-task-registry.service.d.ts +35 -0
- package/lib/services/workspace-task-registry.service.d.ts.map +1 -0
- package/lib/services/workspace-toolbar.service.d.ts +23 -0
- package/lib/services/workspace-toolbar.service.d.ts.map +1 -0
- package/lib/services/workspace.service.d.ts +114 -0
- package/lib/services/workspace.service.d.ts.map +1 -0
- package/lib/storage-keys.d.ts +5 -0
- package/lib/storage-keys.d.ts.map +1 -0
- package/lib/tasks/crud-task/crud-task.component.d.ts +33 -0
- package/lib/tasks/crud-task/crud-task.component.d.ts.map +1 -0
- package/lib/tasks/goto-url-task/goto-url-task.component.d.ts +31 -0
- package/lib/tasks/goto-url-task/goto-url-task.component.d.ts.map +1 -0
- package/lib/workspace/confirm-message-dialog.component.d.ts +16 -0
- package/lib/workspace/confirm-message-dialog.component.d.ts.map +1 -0
- package/lib/workspace/entity-options-dialog.component.d.ts +29 -0
- package/lib/workspace/entity-options-dialog.component.d.ts.map +1 -0
- package/lib/workspace/external-task-api.d.ts +2 -0
- package/lib/workspace/external-task-api.d.ts.map +1 -0
- package/lib/workspace/user-profile-dialog.component.d.ts +30 -0
- package/lib/workspace/user-profile-dialog.component.d.ts.map +1 -0
- package/lib/workspace/workspace-dialog-host.component.d.ts +26 -0
- package/lib/workspace/workspace-dialog-host.component.d.ts.map +1 -0
- package/lib/workspace/workspace-menu-item-dialog.component.d.ts +61 -0
- package/lib/workspace/workspace-menu-item-dialog.component.d.ts.map +1 -0
- package/lib/workspace/workspace-menu.component.d.ts +104 -0
- package/lib/workspace/workspace-menu.component.d.ts.map +1 -0
- package/lib/workspace/workspace-taskbar.component.d.ts +14 -0
- package/lib/workspace/workspace-taskbar.component.d.ts.map +1 -0
- package/package.json +54 -0
- package/public-api.d.ts +56 -0
- package/public-api.d.ts.map +1 -0
- package/service-worker/chill-sharp-service-worker.js +166 -0
- package/styles/core-theme.scss +1268 -0
- package/template-customization/upgrade.ps1.template +342 -0
- package/template-customization/upgrade.sh.template +271 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Verificare La Presenza Di Un Riferimento EF Core Senza Caricarlo
|
|
2
|
+
|
|
3
|
+
English version: [English](../ReferenceExistence.md)
|
|
4
|
+
|
|
5
|
+
`ChillSharp.EF.ChillEntryExtension.Exist()` risponde a una domanda piccola ma utile: questa navigazione di riferimento ha attualmente tutti i valori della chiave esterna configurata?
|
|
6
|
+
|
|
7
|
+
```csharp
|
|
8
|
+
using ChillSharp.EF;
|
|
9
|
+
|
|
10
|
+
var hasCustomerReference = context.Entry(order)
|
|
11
|
+
.Reference(x => x.Customer)
|
|
12
|
+
.Exist();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
La chiamata legge i valori correnti delle proprieta FK dal change tracker di EF Core. Con l'argomento predefinito non esegue query sul database e non carica `order.Customer`.
|
|
16
|
+
|
|
17
|
+
> L'estensione si chiama `Exist`, non `Exists`. La sua firma e `Exist(bool loadIfExist = false)`.
|
|
18
|
+
|
|
19
|
+
## Quando Usarla
|
|
20
|
+
|
|
21
|
+
Usa `Exist()` nella logica del modello che deve distinguere una relazione opzionale assente da una relazione assegnata, evitando un caricamento non necessario dell'entita principale. E utile in particolare in `OnUpdate`, `OnSelect` o nella logica di elaborazione dei DTO quando serve soltanto decidere quale ramo eseguire.
|
|
22
|
+
|
|
23
|
+
```csharp
|
|
24
|
+
public override void OnUpdate(IChillContext context)
|
|
25
|
+
{
|
|
26
|
+
var db = (AppDbContext)context;
|
|
27
|
+
|
|
28
|
+
if (db.Entry(this).Reference(x => x.Customer).Exist())
|
|
29
|
+
{
|
|
30
|
+
// E stato assegnato un valore FK Customer. Customer non e ancora caricato.
|
|
31
|
+
CustomerSummaryRequired = true;
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
{
|
|
35
|
+
CustomerSummaryRequired = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Questo e preferibile a controllare `Customer != null` quando la navigazione puo essere semplicemente non caricata. Una navigazione null non distingue tra “nessuna relazione” e “relazione non caricata”.
|
|
41
|
+
|
|
42
|
+
## Caricamento Opzionale
|
|
43
|
+
|
|
44
|
+
Passa `true` soltanto quando l'operazione successiva ha davvero bisogno dell'entita correlata:
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
var customerReference = context.Entry(order).Reference(x => x.Customer);
|
|
48
|
+
|
|
49
|
+
if (customerReference.Exist(loadIfExist: true) && order.Customer is { } customer)
|
|
50
|
+
{
|
|
51
|
+
// EF Core ha caricato Customer se non era gia caricato.
|
|
52
|
+
var customerName = customer.Name;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Il comportamento e:
|
|
57
|
+
|
|
58
|
+
| Chiamata | Valori FK incompleti o null | Valori FK presenti e navigazione non caricata | Navigazione caricata? |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| `Exist()` | Restituisce `false` | Restituisce `true` | Nessun nuovo caricamento |
|
|
61
|
+
| `Exist(true)` | Restituisce `false` | Restituisce `true` | Prova a caricare il riferimento |
|
|
62
|
+
|
|
63
|
+
Se la navigazione era gia caricata, nessuna delle due forme la carica di nuovo. Poiche il risultato descrive comunque i valori FK, `Exist(true)` puo restituire `true` mentre la navigazione caricata e null se un database senza FK contiene un valore orfano.
|
|
64
|
+
|
|
65
|
+
## Database Senza FK Non Significa Modello Senza Relazione
|
|
66
|
+
|
|
67
|
+
Questa estensione funziona con un'implementazione legacy o con database senza FK solo se EF Core conosce ancora la relazione e le relative proprieta FK del dipendente. Un vincolo fisico nel database e i metadati di relazione di EF Core sono aspetti separati.
|
|
68
|
+
|
|
69
|
+
Per esempio, il database puo non applicare un vincolo da `Order.CustomerGuid` a `Customer.Guid`, ma il modello EF deve comunque avere la FK scalare e il mapping della relazione:
|
|
70
|
+
|
|
71
|
+
```csharp
|
|
72
|
+
public sealed class Order : ChillEntity
|
|
73
|
+
{
|
|
74
|
+
public Guid? CustomerGuid { get; set; }
|
|
75
|
+
public Customer? Customer { get; set; }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
79
|
+
{
|
|
80
|
+
modelBuilder.Entity<Order>()
|
|
81
|
+
.HasOne(x => x.Customer)
|
|
82
|
+
.WithMany()
|
|
83
|
+
.HasForeignKey(x => x.CustomerGuid);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`Exist()` legge `CustomerGuid` tramite questo mapping. Una relazione non configurata in EF Core non ha metadati FK di `ReferenceEntry` che l'estensione possa ispezionare; in quel caso usa direttamente la chiave scalare oppure configura la relazione.
|
|
88
|
+
|
|
89
|
+
Le proprieta FK shadow sono supportate finche EF Core ha mappato la navigazione. L'estensione ottiene i metadati della proprieta FK dalla navigazione, senza richiedere una proprieta FK CLR pubblica.
|
|
90
|
+
|
|
91
|
+
## Significato Del Risultato
|
|
92
|
+
|
|
93
|
+
`Exist()` e un test locale di presenza dei valori FK. Non esegue una query di esistenza per la riga principale.
|
|
94
|
+
|
|
95
|
+
Di conseguenza:
|
|
96
|
+
|
|
97
|
+
- `true` significa che ogni componente FK configurato non e null nell'entry dipendente tracciata.
|
|
98
|
+
- `false` significa che almeno un componente FK e null.
|
|
99
|
+
- `true` non garantisce che la riga correlata esista, soprattutto quando il database non applica vincoli FK oppure contiene valori orfani legacy.
|
|
100
|
+
- `true` non significa che la navigazione sia caricata.
|
|
101
|
+
|
|
102
|
+
Se la regola di business richiede la prova che una riga principale esista, esegui una query esplicita, per esempio con `AnyAsync`, oppure usa `Exist(true)` e gestisci poi una navigazione caricata null. Preferisci la query esplicita quando serve un controllo di esistenza lato server senza materializzare il principale.
|
|
103
|
+
|
|
104
|
+
```csharp
|
|
105
|
+
var customerRowExists = await context.Set<Customer>()
|
|
106
|
+
.AnyAsync(x => x.Guid == order.CustomerGuid, cancellationToken);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Chiavi Composte E Convenzioni Sui Valori
|
|
110
|
+
|
|
111
|
+
Per una FK composta, `Exist()` restituisce `true` soltanto quando ogni componente non e null. Una chiave composta parzialmente popolata restituisce `false`.
|
|
112
|
+
|
|
113
|
+
L'estensione controlla `null`; non valida valori sentinella. Per esempio, `Guid.Empty`, `0` o una stringa vuota non sono null e quindi possono produrre `true` se sono i valori attualmente memorizzati. Usa la validazione appropriata al dominio quando tali valori significano “non assegnato”.
|
|
114
|
+
|
|
115
|
+
## Prerequisiti E Modalita Di Errore
|
|
116
|
+
|
|
117
|
+
L'entita deve essere collegata allo stesso `DbContext` EF Core usato per ottenere la sua entry. Chiama l'estensione sulla navigazione di riferimento dal lato dipendente: l'entita nel `ReferenceEntry` deve possedere le proprieta FK riportate da EF Core per quella navigazione. Chiamarla per un membro che non e un riferimento, per una navigazione senza metadati di relazione FK utilizzabili oppure per la navigazione lato principale di una relazione uno-a-uno puo generare `InvalidOperationException`, poiche le proprieta FK non appartengono all'entry ispezionata.
|
|
118
|
+
|
|
119
|
+
Non usarla per le navigazioni collection. Una collection richiede una domanda diversa—se esiste almeno una riga correlata—che normalmente richiede una query al database.
|
|
120
|
+
|
|
121
|
+
## Guida Alla Scelta
|
|
122
|
+
|
|
123
|
+
| Necessita | Usa |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| Determinare se un riferimento opzionale ha valori FK assegnati senza caricarlo | `Reference(...).Exist()` |
|
|
126
|
+
| Caricare il riferimento soltanto se i valori FK sono assegnati | `Reference(...).Exist(true)` |
|
|
127
|
+
| Provare che la riga principale esiste | Una query esplicita `Any`/`AnyAsync` |
|
|
128
|
+
| Determinare se una collection ha elementi | Una query sul set dipendente |
|
|
129
|
+
|
|
130
|
+
Mantieni `Exist()` per la decisione circoscritta di presenza FK. Il suo valore e rendere esplicito questo intento ed evitare il caricamento di un'entita correlata quando non necessario.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Registrare Un Contesto ChillSharp
|
|
2
|
+
|
|
3
|
+
Versione originale in inglese: [English](../RegisterContext.md)
|
|
4
|
+
|
|
5
|
+
Questo documento mostra come collegare i moduli ChillSharp dentro un host ASP.NET Core.
|
|
6
|
+
|
|
7
|
+
## API Core Minima
|
|
8
|
+
|
|
9
|
+
Per usare solo la Chill API core:
|
|
10
|
+
|
|
11
|
+
```csharp
|
|
12
|
+
using ChillSharp.Api;
|
|
13
|
+
using Microsoft.EntityFrameworkCore;
|
|
14
|
+
|
|
15
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
16
|
+
|
|
17
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
18
|
+
options.UseSqlite("Data Source=app.db"));
|
|
19
|
+
|
|
20
|
+
builder.Services.AddChillApi<AppDbContext>();
|
|
21
|
+
|
|
22
|
+
var app = builder.Build();
|
|
23
|
+
app.MapChillApi();
|
|
24
|
+
app.Run();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Requisiti:
|
|
28
|
+
|
|
29
|
+
- `AppDbContext` deve ereditare `DbContext`
|
|
30
|
+
- `AppDbContext` deve implementare `IChillContext`
|
|
31
|
+
|
|
32
|
+
## Cosa Registra `AddChillApi<TContext>()`
|
|
33
|
+
|
|
34
|
+
La registrazione core configura:
|
|
35
|
+
|
|
36
|
+
- controller ChillSharp
|
|
37
|
+
- risoluzione di `IChillContext` dal contesto host
|
|
38
|
+
- `IChillDtoEngine`
|
|
39
|
+
- comportamento opzionale di API protetta tramite `ChillApiOptions`
|
|
40
|
+
|
|
41
|
+
## Proteggere La Core API
|
|
42
|
+
|
|
43
|
+
Se l'host configura gia autenticazione e autorizzazione, puoi richiedere auth sulla Chill API:
|
|
44
|
+
|
|
45
|
+
```csharp
|
|
46
|
+
builder.Services.AddChillApi<AppDbContext>(options =>
|
|
47
|
+
{
|
|
48
|
+
options.ProtectedApi = true;
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Poi usa il middleware standard ASP.NET Core:
|
|
53
|
+
|
|
54
|
+
```csharp
|
|
55
|
+
app.UseAuthentication();
|
|
56
|
+
app.UseAuthorization();
|
|
57
|
+
app.MapChillApi();
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Aggiungere Servizi Schema
|
|
61
|
+
|
|
62
|
+
Per persistere e servire metadati di schema:
|
|
63
|
+
|
|
64
|
+
```csharp
|
|
65
|
+
using ChillSharp.Schema;
|
|
66
|
+
|
|
67
|
+
builder.Services.AddChillSchema<AppDbContext>();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Requisiti del contesto:
|
|
71
|
+
|
|
72
|
+
- `AppDbContext : IChillSchemaDbContext`
|
|
73
|
+
- `modelBuilder.AddChillSchemaModel()`
|
|
74
|
+
|
|
75
|
+
`ChillSharp.Schema` possiede anche la registrazione della schema cache.
|
|
76
|
+
|
|
77
|
+
## Aggiungere Gestione Auth
|
|
78
|
+
|
|
79
|
+
Per esporre gli endpoint di gestione auth senza i flussi account di ASP.NET Core Identity:
|
|
80
|
+
|
|
81
|
+
```csharp
|
|
82
|
+
using ChillSharp.Auth.Api;
|
|
83
|
+
|
|
84
|
+
builder.Services.AddChillAuthApi<AppDbContext>();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Requisiti del contesto:
|
|
88
|
+
|
|
89
|
+
- `AppDbContext : IChillAuthDbContext`
|
|
90
|
+
- `modelBuilder.AddChillAuthModel()`
|
|
91
|
+
|
|
92
|
+
Questo aggiunge endpoint per:
|
|
93
|
+
|
|
94
|
+
- auth users
|
|
95
|
+
- ruoli
|
|
96
|
+
- assegnazioni utente-ruolo
|
|
97
|
+
- regole di permesso
|
|
98
|
+
- valutazione dei permessi
|
|
99
|
+
|
|
100
|
+
## Aggiungere I Flussi Account Identity
|
|
101
|
+
|
|
102
|
+
Per esporre registrazione account, login, refresh token, cambio password e reset password:
|
|
103
|
+
|
|
104
|
+
```csharp
|
|
105
|
+
using ChillSharp.Auth;
|
|
106
|
+
using ChillSharp.Auth.Api;
|
|
107
|
+
using Microsoft.AspNetCore.Identity;
|
|
108
|
+
|
|
109
|
+
builder.Services.AddIdentityCore<IdentityUser>()
|
|
110
|
+
.AddEntityFrameworkStores<AppDbContext>()
|
|
111
|
+
.AddSignInManager()
|
|
112
|
+
.AddDefaultTokenProviders();
|
|
113
|
+
|
|
114
|
+
builder.Services.AddAuthentication(ChillAuthIdentityDefaults.AuthenticationScheme)
|
|
115
|
+
.AddChillAuthBearer();
|
|
116
|
+
|
|
117
|
+
builder.Services.AddAuthorization();
|
|
118
|
+
|
|
119
|
+
builder.Services.AddChillAuthIdentityApi<AppDbContext, IdentityUser>();
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Questo si appoggia a `AddChillAuthApi<TContext>()`.
|
|
123
|
+
|
|
124
|
+
## Aggiungere I Servizi I18n
|
|
125
|
+
|
|
126
|
+
Per esporre endpoint i18n:
|
|
127
|
+
|
|
128
|
+
```csharp
|
|
129
|
+
using ChillSharp.I18n.Api;
|
|
130
|
+
|
|
131
|
+
builder.Services.AddChillI18nApi<AppDbContext>();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Requisiti del contesto:
|
|
135
|
+
|
|
136
|
+
- `AppDbContext : IChillI18nDbContext`
|
|
137
|
+
- `modelBuilder.AddChillI18nModel()`
|
|
138
|
+
|
|
139
|
+
Il modulo attualmente espone:
|
|
140
|
+
|
|
141
|
+
- `GET /api/chill-i18n/text/{labelGuid}/{cultureName}`
|
|
142
|
+
- `PUT /api/chill-i18n/text`
|
|
143
|
+
|
|
144
|
+
## Esempio Completo Di Host
|
|
145
|
+
|
|
146
|
+
```csharp
|
|
147
|
+
using ChillSharp.Api;
|
|
148
|
+
using ChillSharp.Auth;
|
|
149
|
+
using ChillSharp.Auth.Api;
|
|
150
|
+
using ChillSharp.I18n.Api;
|
|
151
|
+
using ChillSharp.Schema;
|
|
152
|
+
using Microsoft.AspNetCore.Identity;
|
|
153
|
+
using Microsoft.EntityFrameworkCore;
|
|
154
|
+
|
|
155
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
156
|
+
|
|
157
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
158
|
+
options.UseSqlite("Data Source=app.db"));
|
|
159
|
+
|
|
160
|
+
builder.Services.AddIdentityCore<IdentityUser>()
|
|
161
|
+
.AddEntityFrameworkStores<AppDbContext>()
|
|
162
|
+
.AddSignInManager()
|
|
163
|
+
.AddDefaultTokenProviders();
|
|
164
|
+
|
|
165
|
+
builder.Services.AddAuthentication(ChillAuthIdentityDefaults.AuthenticationScheme)
|
|
166
|
+
.AddChillAuthBearer();
|
|
167
|
+
builder.Services.AddAuthorization();
|
|
168
|
+
|
|
169
|
+
builder.Services.AddChillApi<AppDbContext>(options =>
|
|
170
|
+
{
|
|
171
|
+
options.ProtectedApi = true;
|
|
172
|
+
});
|
|
173
|
+
builder.Services.AddChillSchema<AppDbContext>();
|
|
174
|
+
builder.Services.AddChillAuthIdentityApi<AppDbContext, IdentityUser>();
|
|
175
|
+
builder.Services.AddChillI18nApi<AppDbContext>();
|
|
176
|
+
|
|
177
|
+
var app = builder.Build();
|
|
178
|
+
|
|
179
|
+
app.UseAuthentication();
|
|
180
|
+
app.UseAuthorization();
|
|
181
|
+
app.MapChillApi();
|
|
182
|
+
app.Run();
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Comportamento Del Mapping
|
|
186
|
+
|
|
187
|
+
`app.MapChillApi()` mappa i controller ChillSharp e gli endpoint di supporto. Non sostituisce il setup standard del middleware ASP.NET Core. Ti servono comunque:
|
|
188
|
+
|
|
189
|
+
- `UseAuthentication()` se auth e abilitata
|
|
190
|
+
- `UseAuthorization()` se authorization e abilitata
|
|
191
|
+
|
|
192
|
+
I controller i18n e auth vengono aggiunti tramite controller discovery quando i relativi moduli sono registrati.
|
|
193
|
+
|
|
194
|
+
## Ordine Di Startup Consigliato
|
|
195
|
+
|
|
196
|
+
1. registrare il contesto EF Core
|
|
197
|
+
2. registrare Identity se necessario
|
|
198
|
+
3. registrare authentication e authorization se necessario
|
|
199
|
+
4. registrare `AddChillApi<TContext>()`
|
|
200
|
+
5. registrare i moduli opzionali (`Schema`, `Auth`, `I18n`)
|
|
201
|
+
6. build dell'app
|
|
202
|
+
7. applicare il middleware
|
|
203
|
+
8. mappare la Chill API
|
|
204
|
+
|
|
205
|
+
## OpenAPI / Swagger
|
|
206
|
+
|
|
207
|
+
ChillSharp non forza Swagger nel tuo host. Se vuoi output OpenAPI per documentazione o generazione client, aggiungilo nell'app host:
|
|
208
|
+
|
|
209
|
+
```csharp
|
|
210
|
+
builder.Services.AddEndpointsApiExplorer();
|
|
211
|
+
builder.Services.AddSwaggerGen();
|
|
212
|
+
|
|
213
|
+
var app = builder.Build();
|
|
214
|
+
app.UseSwagger();
|
|
215
|
+
app.UseSwaggerUI();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Questa e la base consigliata per generare client TypeScript e Python da un host ChillSharp.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Configurazione del menu CRUD
|
|
2
|
+
|
|
3
|
+
Versione originale in inglese: [English](../../UiCore/CRUD.md)
|
|
4
|
+
|
|
5
|
+
Crea una voce di menu con `ComponentName` impostato a `CRUD`. Il suo `ComponentConfigurationJson` deve essere un oggetto JSON; le chiavi non distinguono maiuscole e minuscole. `chillType` è obbligatorio. Normalmente è il Chill type dell'entità e `chillQuery` è il Chill type della query che restituisce l'entità.
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"chillType": "Model.Post",
|
|
10
|
+
"chillQuery": "Query.PostQuery",
|
|
11
|
+
"viewCode": "default",
|
|
12
|
+
"disableAdd": false,
|
|
13
|
+
"disableCreate": false,
|
|
14
|
+
"disableEdit": false,
|
|
15
|
+
"disableInlineEdit": false,
|
|
16
|
+
"disableDelete": false,
|
|
17
|
+
"defaultValues": {},
|
|
18
|
+
"fixedValues": {},
|
|
19
|
+
"fixedQueryValues": {},
|
|
20
|
+
"defaultQueryValues": {},
|
|
21
|
+
"relations": []
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Opzioni
|
|
26
|
+
|
|
27
|
+
| Chiave | Tipo | Predefinito | Effetto |
|
|
28
|
+
| --- | --- | --- | --- |
|
|
29
|
+
| `chillType` | stringa | obbligatorio | Chill type dell'entità mostrata e modificata dal task. |
|
|
30
|
+
| `chillQuery` | stringa o `null` | `null` | Chill type della query; configuralo quando l'entità richiede una query dedicata. |
|
|
31
|
+
| `viewCode` | stringa | `default` | Codice della vista di schema usato dal task. |
|
|
32
|
+
| `disableAdd` | booleano | `false` | Nasconde il comando Aggiungi. |
|
|
33
|
+
| `disableCreate` | booleano | `false` | Impedisce la creazione di nuovi record. |
|
|
34
|
+
| `disableEdit` | booleano | `false` | Impedisce la modifica nel dialogo. |
|
|
35
|
+
| `disableInlineEdit` | booleano | `false` | Impedisce la modifica inline nella tabella. |
|
|
36
|
+
| `disableDelete` | booleano | `false` | Impedisce l'eliminazione. |
|
|
37
|
+
| `defaultValues` | oggetto | `{}` | Valori iniziali del form di creazione, modificabili dall'utente. |
|
|
38
|
+
| `fixedValues` | oggetto | `{}` | Valori di creazione resi di sola lettura nel form e nell'editor inline. |
|
|
39
|
+
| `fixedQueryValues` | oggetto | `{}` | Filtri query obbligatori che l'utente non può modificare. |
|
|
40
|
+
| `defaultQueryValues` | oggetto | `{}` | Valori iniziali della query che l'utente può modificare. |
|
|
41
|
+
| `relationLabel` | stringa o oggetto | omesso | Etichetta del CRUD aperto come relazione. La forma oggetto è `{ "labelGuid", "primaryDefaultText", "secondaryDefaultText" }`. |
|
|
42
|
+
| `relations` | array | `[]` | Definizioni CRUD figlie disponibili nel menu azioni di ogni riga. |
|
|
43
|
+
|
|
44
|
+
Le proprietà JSON sconosciute sono mantenute dall'editor del menu ma non sono opzioni CRUD standard.
|
|
45
|
+
|
|
46
|
+
## Valori e segnaposto delle relazioni
|
|
47
|
+
|
|
48
|
+
I valori nei quattro oggetti di valori sono valori JSON. In una relazione annidata, la stringa `@{FieldName}` legge quella proprietà dalla riga padre selezionata e `@{mock}` fornisce un oggetto entità leggero per tale riga padre.
|
|
49
|
+
|
|
50
|
+
### Quale contenitore viene applicato e quando
|
|
51
|
+
|
|
52
|
+
Esistono due flussi indipendenti:
|
|
53
|
+
|
|
54
|
+
| Flusso | Valori iniziali modificabili | Valori con precedenza |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| Ricerca/query | `defaultQueryValues` | `fixedQueryValues` |
|
|
57
|
+
| Creazione entità | `defaultValues` | `fixedValues` |
|
|
58
|
+
|
|
59
|
+
UI Core unisce ogni flusso in questo ordine. Se la stessa proprietà compare in entrambi i contenitori, prevale il valore nel contenitore `fixed...`. Usa solo il contenitore fixed quando un valore non deve essere modificato; usa solo quello default quando è soltanto un valore iniziale utile.
|
|
60
|
+
|
|
61
|
+
`fixedQueryValues` vincola i record restituiti dal CRUD figlio. `fixedValues` vincola l'entità inviata dal flusso di creazione e rende tali proprietà di sola lettura nel form e nell'editor inline. I contenitori fixed sono configurazione, non sostituiscono autorizzazione o validazione lato server: l'API deve continuare a imporre tenant, proprietà e autorizzazioni.
|
|
62
|
+
|
|
63
|
+
### Valori statici compatibili con CLR
|
|
64
|
+
|
|
65
|
+
Il letterale JSON viene passato come valore della proprietà; UI Core non lo valuta né lo converte prima della normale serializzazione di entità/query. Usa la rappresentazione JSON attesa dall'API ChillSharp per la proprietà CLR.
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"defaultQueryValues": {
|
|
70
|
+
"IsPublished": true,
|
|
71
|
+
"MinimumScore": 50,
|
|
72
|
+
"Category": "News",
|
|
73
|
+
"From": "2026-01-01T00:00:00+01:00"
|
|
74
|
+
},
|
|
75
|
+
"fixedValues": {
|
|
76
|
+
"TenantCode": "acme",
|
|
77
|
+
"Priority": 10,
|
|
78
|
+
"IsInternal": false,
|
|
79
|
+
"ArchivedAt": null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Usa stringhe JSON per `string`, `Guid`, `DateTime`, `DateTimeOffset`, `DateOnly` CLR e per gli enum che il server espone come stringhe. Usa numeri JSON per valori CLR numerici e booleani JSON per `bool`. Date e GUID devono essere stringhe JSON, non espressioni JavaScript: `"2026-01-01"` e `"8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b"`, non `new Date(...)` o `Guid.NewGuid()`.
|
|
85
|
+
|
|
86
|
+
### Valori statici di riferimento a entità
|
|
87
|
+
|
|
88
|
+
Sì: un riferimento a entità può essere statico poiché un oggetto JSON è un valore ammesso. Fornisci la stessa forma di riferimento accettata dalla proprietà destinazione, normalmente almeno identificatore e tipo dell'entità riferita:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"fixedQueryValues": {
|
|
93
|
+
"Customer": {
|
|
94
|
+
"guid": "8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b",
|
|
95
|
+
"chillType": "Model.Customer"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"fixedValues": {
|
|
99
|
+
"Status": {
|
|
100
|
+
"guid": "7d8af0dd-d20d-4bb7-9a4d-f3b9d2f9c2b4",
|
|
101
|
+
"chillType": "Model.OrderStatus",
|
|
102
|
+
"label": "Approved"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`label` è metadato UI facoltativo. Non usarlo come identità: l'entità è identificata da `guid`. Includi `chillType` quando il riferimento può essere polimorfico o quando server/client richiedono informazioni di tipo esplicite. Il nome della proprietà e la forma dell'oggetto devono corrispondere allo schema query o entità destinazione; una proprietà di chiave esterna scalare richiede invece la stringa GUID scalare, ad esempio `"CustomerGuid": "8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b"`.
|
|
109
|
+
|
|
110
|
+
### Valori dinamici: `@{FieldName}` e `@{mock}`
|
|
111
|
+
|
|
112
|
+
I segnaposto vengono risolti solo aprendo una relazione dalla riga padre selezionata. Non sono espressioni e non vengono valutati in un CRUD menu radice, perché non esiste un'entità padre. In quel caso la stringa del segnaposto rimane invariata.
|
|
113
|
+
|
|
114
|
+
- `@{Guid}` copia il valore `Guid`/`guid` della riga selezionata.
|
|
115
|
+
- `@{CustomerCode}` copia un campo dall'oggetto `properties` della riga selezionata o dalle proprietà dirette dell'oggetto. Un token camel-case usa anche come fallback il nome della proprietà Pascal-case.
|
|
116
|
+
- Un campo mancante viene risolto a `null`.
|
|
117
|
+
- `@{mock}` crea una copia leggera dell'entità padre selezionata. Contiene `guid`, `chillType`, `label` e una copia di `properties`; non recupera nuovamente l'entità.
|
|
118
|
+
|
|
119
|
+
Usa `@{mock}` per una proprietà di riferimento figlia come `Order` e `@{Guid}` per una chiave esterna scalare come `OrderGuid`:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"relations": [
|
|
124
|
+
{
|
|
125
|
+
"chillType": "Model.OrderRow",
|
|
126
|
+
"chillQuery": "Query.OrderRowQuery",
|
|
127
|
+
"fixedQueryValues": { "Order": "@{mock}" },
|
|
128
|
+
"defaultQueryValues": { "Order": "@{mock}" },
|
|
129
|
+
"fixedValues": { "Order": "@{mock}" },
|
|
130
|
+
"defaultValues": { "Order": "@{mock}" }
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"chillType": "Model.OrderRow",
|
|
134
|
+
"chillQuery": "Query.OrderRowQuery",
|
|
135
|
+
"fixedQueryValues": { "OrderGuid": "@{Guid}" },
|
|
136
|
+
"fixedValues": { "OrderGuid": "@{Guid}" }
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Usa la prima forma solo quando lo schema query/entità espone una proprietà riferimento-entità `Order`. Usa la seconda solo quando espone una proprietà scalare `OrderGuid`. Non inviare `@{mock}` a una proprietà GUID scalare.
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"chillType": "Model.Order",
|
|
147
|
+
"chillQuery": "Query.OrderQuery",
|
|
148
|
+
"relations": [
|
|
149
|
+
{
|
|
150
|
+
"chillType": "Model.OrderRow",
|
|
151
|
+
"chillQuery": "Query.OrderRowQuery",
|
|
152
|
+
"relationLabel": {
|
|
153
|
+
"labelGuid": "ORDER-ROWS-LABEL",
|
|
154
|
+
"primaryDefaultText": "Rows",
|
|
155
|
+
"secondaryDefaultText": "Righe"
|
|
156
|
+
},
|
|
157
|
+
"fixedQueryValues": { "Order": "@{mock}" },
|
|
158
|
+
"defaultQueryValues": { "Order": "@{mock}" },
|
|
159
|
+
"defaultValues": { "Order": "@{mock}" },
|
|
160
|
+
"fixedValues": { "Order": "@{mock}" }
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Usa `fixedQueryValues` per un filtro padre non modificabile e `defaultQueryValues` per un filtro iniziale modificabile. Usa `fixedValues` per un valore di creazione di sola lettura e `defaultValues` per un valore iniziale di creazione modificabile. Le relazioni possono contenere ulteriori array `relations`.
|
|
167
|
+
|
|
168
|
+
## Persistenza della voce di menu
|
|
169
|
+
|
|
170
|
+
L'API menu memorizza il JSON come stringa. Per esempio, usa `ComponentName: "CRUD"` e serializza l'oggetto in `ComponentConfigurationJson` quando chiami `set-menu`. JSON non valido, oppure un array JSON al posto di un oggetto, non può configurare il task.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# ChillSharp UI Core
|
|
2
|
+
|
|
3
|
+
Versione originale in inglese: [English](../../UiCore/README.md)
|
|
4
|
+
|
|
5
|
+
`@chill-sharp/ui-core` è l'interfaccia Angular condivisa a workspace per le applicazioni ChillSharp. Fornisce il contenitore del workspace, la navigazione autenticata, form e tabelle guidati dallo schema, task CRUD, schermate dei permessi e il registro dei task di menu. I repository applicativi mantengono fuori da questo pacchetto branding del tenant, route, configurazione runtime ed estensioni di proprietà del client.
|
|
6
|
+
|
|
7
|
+
Il pacchetto legge i metadati di schema e menu dall'API ChillSharp. Il server controlla i metadati delle entità e le voci di menu persistite; UI Core visualizza l'esperienza standard a partire da tali metadati. Usa JSON di configurazione per personalizzare un singolo task di menu senza copiare il codice UI condiviso.
|
|
8
|
+
|
|
9
|
+
## Guide
|
|
10
|
+
|
|
11
|
+
- [Configurazione del menu CRUD](./CRUD.md): configurare una voce menu `CRUD` e le relative opzioni JSON.
|
|
12
|
+
- [Guida ai menu](../MenuGuide/README.md): voci di menu persistite e visibilità `MenuHierarchy`.
|
|
13
|
+
- [Configurazione delle relazioni](../MenuGuide/Relations.md): relazioni di schema che UI Core può trasformare in task CRUD annidati.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Modello di convalida
|
|
2
|
+
|
|
3
|
+
Versione originale in inglese: [English](../../ValidationModel/README.md)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
ChillSharp supporta gli attributi di convalida ASP.NET Core/.NET standard sulle proprietà di entità e query, purché tali proprietà siano contrassegnate anche con `[ChillProperty]`.
|
|
7
|
+
|
|
8
|
+
## Convalida standard sulle proprietà Chill
|
|
9
|
+
|
|
10
|
+
Decora le tue proprietà `ChillEntity` o `ChillQuery` sia con `[ChillProperty]` che con i consueti attributi DataAnnotations come `[Required]`, `[StringLength]`, `[Range]`, `[EmailAddress]` e così via.
|
|
11
|
+
|
|
12
|
+
```csharp
|
|
13
|
+
using ChillSharp.Annotations;
|
|
14
|
+
using ChillSharp.EF;
|
|
15
|
+
using System.ComponentModel.DataAnnotations;
|
|
16
|
+
|
|
17
|
+
public class Customer : ChillEntity
|
|
18
|
+
{
|
|
19
|
+
[Key]
|
|
20
|
+
public override Guid Guid { get; set; }
|
|
21
|
+
|
|
22
|
+
[ChillProperty(
|
|
23
|
+
UniquePropertyKeyString: "2F262D7E-F676-4857-B41D-D31C766AA38F",
|
|
24
|
+
PrimaryLanguageLabel: "Name",
|
|
25
|
+
SecondaryLanguageLabel: "Nome")]
|
|
26
|
+
[Required(ErrorMessage = "Customer name is required.")]
|
|
27
|
+
[StringLength(80, ErrorMessage = "Customer name must be 80 characters or less.")]
|
|
28
|
+
public string Name { get; set; } = string.Empty;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
In fase di esecuzione ChillSharp convalida solo le proprietà decorate con `[ChillProperty]`.
|
|
33
|
+
|
|
34
|
+
Se una proprietà ha attributi DataAnnotations ma non è una proprietà Chill, ChillSharp la ignora nella pipeline di convalida Chill.
|
|
35
|
+
|
|
36
|
+
## Combinazione di DataAnnotations con `OnValidation()`
|
|
37
|
+
|
|
38
|
+
È comunque possibile aggiungere una convalida ChillSharp personalizzata sovrascrivendo `OnValidation()`.
|
|
39
|
+
|
|
40
|
+
```csharp
|
|
41
|
+
public override IEnumerable<ChillValidationError> OnValidation(IChillContext context)
|
|
42
|
+
{
|
|
43
|
+
if (Name == "admin")
|
|
44
|
+
{
|
|
45
|
+
return
|
|
46
|
+
[
|
|
47
|
+
new ChillValidationError
|
|
48
|
+
{
|
|
49
|
+
FieldName = nameof(Name),
|
|
50
|
+
Message = "The name 'admin' is reserved."
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Il comportamento in fase di esecuzione è:
|
|
60
|
+
|
|
61
|
+
1. ChillSharp esegue la convalida DataAnnotations standard sui membri `[ChillProperty]`.
|
|
62
|
+
2. ChillSharp esegue quindi la logica `OnValidation()` personalizzata.
|
|
63
|
+
3. Gli errori restituiti vengono esposti come `ChillValidationError` utilizzando le DataAnnotations leggibili dall'uomo `ErrorMessage`.
|
|
64
|
+
|
|
65
|
+
## Aggiorna il comportamento
|
|
66
|
+
|
|
67
|
+
La stessa pipeline di convalida viene eseguita automaticamente anche all'inizio dell'hook runtime post-aggiornamento interno utilizzato da ChillSharp.
|
|
68
|
+
|
|
69
|
+
Ciò significa:
|
|
70
|
+
|
|
71
|
+
-Se il client chiama la convalida in modo esplicito, riceve voci `ChillValidationError` per errori di convalida personalizzati e basati su annotazioni.
|
|
72
|
+
- Se il client salta la convalida esplicita e passa direttamente alla creazione o all'aggiornamento, ChillSharp convalida comunque l'entità durante il ciclo di vita dell'aggiornamento e genera un `ChillValidationException` con gli stessi messaggi leggibili dall'uomo.
|
|
73
|
+
|
|
74
|
+
## Note
|
|
75
|
+
|
|
76
|
+
- Utilizza DataAnnotations standard per semplici regole di campo.
|
|
77
|
+
- Utilizzare `OnValidation()` per regole che dipendono da più campi, logica aziendale o ricerche nel database.
|
|
78
|
+
- Per rendere una proprietà parte della convalida ChillSharp, aggiungere sempre `[ChillProperty]`.
|
|
79
|
+
|
|
80
|
+
## Appendice: messaggi di convalida basati su GUID
|
|
81
|
+
|
|
82
|
+
Come hack di flessibilità opzionale, un DataAnnotations `ErrorMessage` può contenere una stringa GUID invece del testo dell'utente finale.
|
|
83
|
+
|
|
84
|
+
Quindi puoi fornire i testi primari e secondari effettivi sovrascrivendo `GetValidationMessageDefinitions()`.
|
|
85
|
+
|
|
86
|
+
```csharp
|
|
87
|
+
public class Customer : ChillEntity
|
|
88
|
+
{
|
|
89
|
+
[ChillProperty(
|
|
90
|
+
UniquePropertyKeyString: "B2AB35A8-6A89-4D39-8F1D-183F686811A9",
|
|
91
|
+
PrimaryLanguageLabel: "Code",
|
|
92
|
+
SecondaryLanguageLabel: "Codice")]
|
|
93
|
+
[Required(ErrorMessage = "4F880CC1-5C7A-4E23-982A-5F0C490B44DE")]
|
|
94
|
+
public string Code { get; set; } = string.Empty;
|
|
95
|
+
|
|
96
|
+
public override IEnumerable<ChillValidationMessageDefinition> GetValidationMessageDefinitions(IChillContext context)
|
|
97
|
+
{
|
|
98
|
+
return
|
|
99
|
+
[
|
|
100
|
+
new ChillValidationMessageDefinition
|
|
101
|
+
{
|
|
102
|
+
MessageGuid = Guid.Parse("4F880CC1-5C7A-4E23-982A-5F0C490B44DE"),
|
|
103
|
+
PrimaryLanguageMessage = "Code is required.",
|
|
104
|
+
SecondaryLanguageMessage = "Il codice e obbligatorio."
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Quando ChillSharp vede il GUID in `ErrorMessage`, risolve il messaggio finale attraverso la stessa convenzione di lingua primaria/secondaria utilizzata altrove nei metadati di ChillSharp.
|
|
112
|
+
|
|
113
|
+
Note:
|
|
114
|
+
|
|
115
|
+
- Questo è facoltativo. I semplici valori `ErrorMessage` leggibili dall'uomo funzionano ancora normalmente.
|
|
116
|
+
- Utilizzalo solo quando desideri un identificatore stabile per un testo di convalida.
|
|
117
|
+
- Se il GUID non viene trovato in `GetValidationMessageDefinitions()`, ChillSharp torna alla stringa grezza `ErrorMessage`.
|