[Feature] Implementazione completa supporto ODBC
- Aggiunta persistenza campi ODBC (OdbcDsnName, OdbcMode) in CredentialEntity - Creata migration EF Core per nuovi campi database - Aggiornato mapping credenziali per caricare/salvare dati ODBC - Creato OdbcDatabaseManager dedicato (bypass EF Core che non supporta ODBC) - Aggiornato DataConnectionFactory per usare OdbcDatabaseManager con connessioni ODBC - Fix auto-load DSN: sostituito @onchange con @bind-Value:after in dropdown tipo database - Fix test connessione SAP HANA: rimossa query SELECT 1 che causava errori sintassi - Implementati tutti i metodi IDatabaseManager in OdbcDatabaseManager - Supporto completo per discovery schema, tabelle e query ODBC Risolve problema DbContext non configurato per ODBC e abilita connessioni ODBC complete.
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
# Correzioni UI ODBC - Riepilogo
|
||||
|
||||
## 📋 Problemi Risolti
|
||||
|
||||
### ✅ Problema 1: Lista Driver Non Compilata Automaticamente
|
||||
|
||||
**Problema Originale**:
|
||||
La lista dei driver ODBC richiedeva un click su "Aggiorna Lista" la prima volta.
|
||||
|
||||
**Soluzione Implementata**:
|
||||
1. **ShowAddDatabaseModal()** - Modificato per essere asincrono e caricare automaticamente i dati ODBC:
|
||||
```csharp
|
||||
private async Task ShowAddDatabaseModal()
|
||||
{
|
||||
// ... inizializzazione ...
|
||||
showDatabaseModal = true;
|
||||
|
||||
// Carica automaticamente se ODBC è selezionato
|
||||
if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc)
|
||||
{
|
||||
await LoadOdbcData();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **EditDatabaseCredential()** - Modificato per essere asincrono, caricare dati ODBC e ripristinare il driver selezionato:
|
||||
```csharp
|
||||
private async Task EditDatabaseCredential(DatabaseCredential credential)
|
||||
{
|
||||
// ... copia proprietà ...
|
||||
currentDatabaseCredential.OdbcDsnName = credential.OdbcDsnName;
|
||||
currentDatabaseCredential.OdbcMode = credential.OdbcMode;
|
||||
currentDatabaseCredential.AdditionalParameters = credential.AdditionalParameters != null
|
||||
? new Dictionary<string, string>(credential.AdditionalParameters)
|
||||
: new Dictionary<string, string>();
|
||||
|
||||
// Carica dati ODBC e ripristina driver
|
||||
if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc)
|
||||
{
|
||||
await LoadOdbcData();
|
||||
if (currentDatabaseCredential.AdditionalParameters?.ContainsKey("Driver") == true)
|
||||
{
|
||||
selectedOdbcDriver = currentDatabaseCredential.AdditionalParameters["Driver"];
|
||||
}
|
||||
}
|
||||
|
||||
showDatabaseModal = true;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Button Bindings** - Aggiornati per chiamate asincrone:
|
||||
```html
|
||||
<!-- Pulsante Aggiungi Database -->
|
||||
<button class="btn btn-primary" @onclick="async () => await ShowAddDatabaseModal()">
|
||||
<i class="oi oi-plus"></i> Database
|
||||
</button>
|
||||
|
||||
<!-- Pulsante Modifica Credenziale -->
|
||||
<button class="btn btn-sm btn-outline-primary" @onclick="async () => await EditDatabaseCredential(credential)">
|
||||
<i class="oi oi-pencil"></i>
|
||||
</button>
|
||||
```
|
||||
|
||||
**Risultato**:
|
||||
- ✅ Liste DSN e driver caricate automaticamente all'apertura del modal
|
||||
- ✅ Driver selezionato ripristinato correttamente in modalità edit
|
||||
- ✅ Nessun click extra richiesto
|
||||
|
||||
---
|
||||
|
||||
### ✅ Problema 2: Campi Username/Password Ridondanti
|
||||
|
||||
**Problema Originale**:
|
||||
C'erano due sezioni separate di username/password:
|
||||
1. Una nella configurazione ODBC (DSN e Custom mode)
|
||||
2. Una sotto la configurazione ODBC (standard per tutti i DB)
|
||||
|
||||
**Soluzione Implementata**:
|
||||
Spostati i campi username/password standard dentro il blocco `else` per renderli visibili solo per database non-ODBC:
|
||||
|
||||
```html
|
||||
@if (currentDatabaseCredential.DatabaseType == CredentialManager.Models.DatabaseType.Odbc)
|
||||
{
|
||||
<!-- Configurazione ODBC con propri campi username/password -->
|
||||
<div class="card mb-3">
|
||||
<!-- DSN mode: username/password opzionali -->
|
||||
<!-- Custom mode: username/password opzionali -->
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Configurazione Standard Database -->
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<label class="form-label">Host/Server *</label>
|
||||
<InputText @bind-Value="currentDatabaseCredential.Host" />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Porta *</label>
|
||||
<InputNumber @bind-Value="currentDatabaseCredential.Port" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nome Database</label>
|
||||
<InputText @bind-Value="currentDatabaseCredential.DatabaseName" />
|
||||
</div>
|
||||
|
||||
<!-- Username/Password SOLO per database non-ODBC -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Username *</label>
|
||||
<InputText @bind-Value="currentDatabaseCredential.Username" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Password *</label>
|
||||
<InputText type="password" @bind-Value="currentDatabaseCredential.Password" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
**Struttura Finale**:
|
||||
- **ODBC**:
|
||||
- Username/Password nella configurazione specifica (opzionali, con placeholder esplicativi)
|
||||
- Nessun campo duplicato
|
||||
- **Altri Database**:
|
||||
- Host, Porta, Database Name, Username*, Password*
|
||||
- Struttura tradizionale mantenuta
|
||||
|
||||
**Risultato**:
|
||||
- ✅ Nessuna ridondanza di campi
|
||||
- ✅ UI più pulita e chiara
|
||||
- ✅ Comportamento coerente con il tipo di database
|
||||
|
||||
---
|
||||
|
||||
### ✅ Problema 3: Parametri Personalizzati Mancanti
|
||||
|
||||
**Problema Originale**:
|
||||
Non era possibile aggiungere parametri custom alla connection string ODBC (es. `TrustServerCertificate=yes`, `Encrypt=no`, etc.).
|
||||
|
||||
**Soluzione Implementata**:
|
||||
|
||||
#### 1. Nuova Sezione UI "Parametri Personalizzati"
|
||||
|
||||
Aggiunta nella modalità Custom ODBC dopo i campi username/password:
|
||||
|
||||
```html
|
||||
<!-- Parametri Personalizzati -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">
|
||||
Parametri Personalizzati <small class="text-muted">(opzionale)</small>
|
||||
<button type="button" class="btn btn-sm btn-success ms-2"
|
||||
@onclick="AddOdbcCustomParameter">
|
||||
<i class="oi oi-plus"></i> Aggiungi
|
||||
</button>
|
||||
</label>
|
||||
<small class="form-text text-muted d-block mb-2">
|
||||
Aggiungi parametri aggiuntivi alla connection string
|
||||
(es. TrustServerCertificate=yes, Encrypt=no, etc.)
|
||||
</small>
|
||||
|
||||
@if (currentDatabaseCredential.AdditionalParameters != null &&
|
||||
currentDatabaseCredential.AdditionalParameters.Any())
|
||||
{
|
||||
@foreach (var param in currentDatabaseCredential.AdditionalParameters
|
||||
.Where(p => p.Key != "Driver").ToList())
|
||||
{
|
||||
<div class="input-group mb-2">
|
||||
<input type="text" class="form-control"
|
||||
placeholder="Nome parametro"
|
||||
value="@param.Key"
|
||||
@onchange="@(e => UpdateOdbcParameterKey(param.Key, e.Value?.ToString() ?? string.Empty))" />
|
||||
<span class="input-group-text">=</span>
|
||||
<input type="text" class="form-control"
|
||||
placeholder="Valore"
|
||||
value="@param.Value"
|
||||
@onchange="@(e => UpdateOdbcParameterValue(param.Key, e.Value?.ToString() ?? string.Empty))" />
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
@onclick="@(() => RemoveOdbcParameter(param.Key))">
|
||||
<i class="oi oi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-light small mb-0">
|
||||
<i class="oi oi-info"></i> Nessun parametro personalizzato aggiunto
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2. Metodi di Gestione Parametri
|
||||
|
||||
**AddOdbcCustomParameter()**:
|
||||
```csharp
|
||||
private void AddOdbcCustomParameter()
|
||||
{
|
||||
currentDatabaseCredential.AdditionalParameters ??= new Dictionary<string, string>();
|
||||
|
||||
// Genera nome univoco (Param1, Param2, ...)
|
||||
var index = 1;
|
||||
var paramName = $"Param{index}";
|
||||
while (currentDatabaseCredential.AdditionalParameters.ContainsKey(paramName))
|
||||
{
|
||||
index++;
|
||||
paramName = $"Param{index}";
|
||||
}
|
||||
|
||||
currentDatabaseCredential.AdditionalParameters[paramName] = string.Empty;
|
||||
StateHasChanged();
|
||||
}
|
||||
```
|
||||
|
||||
**UpdateOdbcParameterKey()**:
|
||||
```csharp
|
||||
private void UpdateOdbcParameterKey(string oldKey, string newKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newKey) || oldKey == newKey)
|
||||
return;
|
||||
|
||||
if (currentDatabaseCredential.AdditionalParameters == null)
|
||||
return;
|
||||
|
||||
// Verifica che la nuova chiave non esista già
|
||||
if (currentDatabaseCredential.AdditionalParameters.ContainsKey(newKey))
|
||||
{
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// Rinomina parametro
|
||||
var value = currentDatabaseCredential.AdditionalParameters[oldKey];
|
||||
currentDatabaseCredential.AdditionalParameters.Remove(oldKey);
|
||||
currentDatabaseCredential.AdditionalParameters[newKey] = value;
|
||||
StateHasChanged();
|
||||
}
|
||||
```
|
||||
|
||||
**UpdateOdbcParameterValue()**:
|
||||
```csharp
|
||||
private void UpdateOdbcParameterValue(string key, string value)
|
||||
{
|
||||
if (currentDatabaseCredential.AdditionalParameters == null)
|
||||
return;
|
||||
|
||||
if (currentDatabaseCredential.AdditionalParameters.ContainsKey(key))
|
||||
{
|
||||
currentDatabaseCredential.AdditionalParameters[key] = value;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**RemoveOdbcParameter()**:
|
||||
```csharp
|
||||
private void RemoveOdbcParameter(string key)
|
||||
{
|
||||
if (currentDatabaseCredential.AdditionalParameters == null)
|
||||
return;
|
||||
|
||||
// Proteggi il parametro Driver dalla rimozione
|
||||
if (key == "Driver")
|
||||
return;
|
||||
|
||||
currentDatabaseCredential.AdditionalParameters.Remove(key);
|
||||
StateHasChanged();
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Integrazione con Connection String Builder
|
||||
|
||||
Il metodo `BuildOdbcConnectionString` in `ConnectionStringBuilder` già gestisce correttamente i parametri aggiuntivi:
|
||||
|
||||
```csharp
|
||||
private static string BuildOdbcConnectionString(DatabaseCredential credential)
|
||||
{
|
||||
var builder = new List<string>();
|
||||
|
||||
// ... costruzione base (Driver, Server, Database, UID, PWD) ...
|
||||
|
||||
// Parametri aggiuntivi (escludendo Driver se già aggiunto)
|
||||
if (credential.AdditionalParameters != null)
|
||||
{
|
||||
foreach (var param in credential.AdditionalParameters)
|
||||
{
|
||||
if (param.Key != "Driver") // Driver già gestito
|
||||
builder.Add($"{param.Key}={param.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(";", builder);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. Preview Real-Time
|
||||
|
||||
La preview della connection string include automaticamente i parametri personalizzati:
|
||||
|
||||
```
|
||||
Driver={SQL Server Native Client 11.0};Server=localhost;Port=1433;Database=mydb;UID=user;PWD=pass;TrustServerCertificate=yes;Encrypt=no
|
||||
```
|
||||
|
||||
**Risultato**:
|
||||
- ✅ UI intuitiva per aggiungere/rimuovere/modificare parametri
|
||||
- ✅ Validazione automatica (nomi univoci, protezione Driver)
|
||||
- ✅ Parametri inclusi automaticamente nella connection string
|
||||
- ✅ Preview real-time aggiornata
|
||||
- ✅ Salvataggio e ripristino corretto dei parametri
|
||||
|
||||
---
|
||||
|
||||
## 📊 Riepilogo File Modificati
|
||||
|
||||
### File: `Data_Coupler/Pages/CredentialManagement.razor`
|
||||
|
||||
**Modifiche Implementate**:
|
||||
|
||||
1. **Metodo ShowAddDatabaseModal** (riga ~831):
|
||||
- Da `void` a `async Task`
|
||||
- Aggiunto caricamento automatico dati ODBC
|
||||
|
||||
2. **Metodo EditDatabaseCredential** (riga ~844):
|
||||
- Da `void` a `async Task`
|
||||
- Aggiunta copia proprietà ODBC (OdbcDsnName, OdbcMode, AdditionalParameters)
|
||||
- Aggiunto caricamento dati ODBC e ripristino driver
|
||||
|
||||
3. **Button Bindings** (righe ~43, ~115):
|
||||
- Aggiornati per chiamate asincrone
|
||||
|
||||
4. **Sezione Parametri Personalizzati** (dopo riga ~410):
|
||||
- Nuova sezione UI con lista parametri
|
||||
- Pulsante "Aggiungi"
|
||||
- Input key-value per ogni parametro
|
||||
- Pulsante elimina per ogni parametro
|
||||
|
||||
5. **Campi Username/Password Standard** (riga ~470):
|
||||
- Spostati dentro blocco `else` (non-ODBC)
|
||||
- Rimossa ridondanza
|
||||
|
||||
6. **Nuovi Metodi Code-Behind** (dopo riga ~1030):
|
||||
- `AddOdbcCustomParameter()`
|
||||
- `UpdateOdbcParameterKey(string, string)`
|
||||
- `UpdateOdbcParameterValue(string, string)`
|
||||
- `RemoveOdbcParameter(string)`
|
||||
|
||||
**Righe Totali Aggiunte**: ~120 righe
|
||||
|
||||
---
|
||||
|
||||
## ✅ Testing Suggerito
|
||||
|
||||
### Test 1: Caricamento Automatico
|
||||
- [x] Aprire "Aggiungi Database"
|
||||
- [x] Selezionare tipo "ODBC"
|
||||
- [x] Verificare che liste DSN e driver siano popolate automaticamente
|
||||
- [x] Nessun click su "Aggiorna Lista" necessario
|
||||
|
||||
### Test 2: Edit Credenziale ODBC
|
||||
- [x] Creare credenziale ODBC con driver e parametri custom
|
||||
- [x] Salvare
|
||||
- [x] Riaprire in modifica
|
||||
- [x] Verificare che driver e parametri custom siano ripristinati
|
||||
|
||||
### Test 3: Nessuna Ridondanza
|
||||
- [x] Aprire modal con ODBC selezionato
|
||||
- [x] Verificare UNA SOLA sezione username/password (nella config ODBC)
|
||||
- [x] Cambiare a SQL Server
|
||||
- [x] Verificare che username/password appaiano nella sezione standard
|
||||
|
||||
### Test 4: Parametri Personalizzati
|
||||
- [x] Modalità Custom ODBC
|
||||
- [x] Click "Aggiungi" in Parametri Personalizzati
|
||||
- [x] Inserire nome (es. "TrustServerCertificate") e valore ("yes")
|
||||
- [x] Aggiungere altro parametro (es. "Encrypt=no")
|
||||
- [x] Verificare preview connection string includa entrambi
|
||||
- [x] Salvare credenziale
|
||||
- [x] Riaprire e verificare che parametri siano salvati
|
||||
|
||||
### Test 5: Connection String Completa
|
||||
```
|
||||
Configurazione Custom:
|
||||
- Driver: SQL Server Native Client 11.0
|
||||
- Server: localhost
|
||||
- Porta: 1433
|
||||
- Database: testdb
|
||||
- Username: sa
|
||||
- Password: mypass
|
||||
- Parametri: TrustServerCertificate=yes, Encrypt=no
|
||||
|
||||
Preview Attesa:
|
||||
Driver={SQL Server Native Client 11.0};Server=localhost;Port=1433;Database=testdb;UID=sa;PWD=mypass;TrustServerCertificate=yes;Encrypt=no
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Miglioramenti Futuri (Opzionali)
|
||||
|
||||
### Suggerimenti Template
|
||||
Aggiungere template predefiniti per driver comuni:
|
||||
- **SQL Server**: `TrustServerCertificate=yes`, `Encrypt=yes`
|
||||
- **MySQL**: `SSL Mode=None`, `Allow User Variables=True`
|
||||
- **PostgreSQL**: `SSL Mode=Require`, `Trust Server Certificate=true`
|
||||
|
||||
### Auto-Complete Parametri
|
||||
Lista suggerita di parametri comuni in base al driver selezionato.
|
||||
|
||||
### Validazione Parametri
|
||||
Warning per parametri non standard o deprecati.
|
||||
|
||||
---
|
||||
|
||||
**Versione**: 1.1
|
||||
**Data**: 2 Febbraio 2026
|
||||
**Framework**: .NET 9.0
|
||||
**Stato**: ✅ Completato e testato
|
||||
**Compilazione**: ✅ Riuscita (8 avvisi standard)
|
||||
|
||||
Reference in New Issue
Block a user