[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:
Alessio Dal Santo
2026-02-02 18:24:44 +01:00
parent e7fb9a5cc7
commit 01f78466df
22 changed files with 3615 additions and 49 deletions
+250
View File
@@ -0,0 +1,250 @@
# Fix ODBC: Caricamento DSN e Validazione Connessione
## 🐛 Problemi Risolti
### Problema 1: DSN Non Caricati Automaticamente
**Sintomo**: Lista DSN vuota all'apertura della form ODBC, richiedeva click su "Aggiorna Lista"
**Causa**: `OnDatabaseTypeChanged` non veniva chiamato automaticamente quando si apriva la form con ODBC
**Soluzione**:
Già implementata correttamente in precedenza:
- `ShowAddDatabaseModal()` ora carica automaticamente dati ODBC
- `EditDatabaseCredential()` carica dati ODBC e ripristina driver
- `OnDatabaseTypeChanged()` carica dati quando si cambia tipo
**Status**: Risolto
---
### Problema 2: Test Connessione Fallisce per ODBC
**Sintomo**: Errore "Compila tutti i campi obbligatori prima di testare la connessione" anche con form ODBC completa
**Causa**: `TestCurrentDatabaseConnection()` validava sempre Host, Username, Password - non appropriati per ODBC DSN mode
**Soluzione Implementata**:
```csharp
private async Task TestCurrentDatabaseConnection()
{
if (testingConnection) return;
testingConnection = true;
try
{
// Validazione base: Nome sempre obbligatorio
if (string.IsNullOrEmpty(currentDatabaseCredential.Name))
{
await JSRuntime.InvokeVoidAsync("alert", "Il nome della credenziale è obbligatorio.");
return;
}
// Validazione specifica per tipo database
if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc)
{
// ODBC: Validazione in base alla modalità
if (currentDatabaseCredential.OdbcMode == OdbcConnectionMode.Dsn)
{
// Modalità DSN: richiede DSN selezionato
if (string.IsNullOrEmpty(currentDatabaseCredential.OdbcDsnName))
{
await JSRuntime.InvokeVoidAsync("alert", "Seleziona un DSN ODBC.");
return;
}
}
else
{
// Modalità Custom: richiede driver e host
if (!currentDatabaseCredential.AdditionalParameters?.ContainsKey("Driver") ?? true)
{
await JSRuntime.InvokeVoidAsync("alert", "Seleziona un driver ODBC.");
return;
}
if (string.IsNullOrEmpty(currentDatabaseCredential.Host))
{
await JSRuntime.InvokeVoidAsync("alert", "Inserisci il server/host.");
return;
}
}
}
else
{
// Altri database: validazione standard (Host, Username, Password)
if (string.IsNullOrEmpty(currentDatabaseCredential.Host) ||
string.IsNullOrEmpty(currentDatabaseCredential.Username) ||
string.IsNullOrEmpty(currentDatabaseCredential.Password))
{
await JSRuntime.InvokeVoidAsync("alert", "Compila tutti i campi obbligatori (Host, Username, Password).");
return;
}
}
var (success, message) = await CredentialService.TestDatabaseConnectionAsync(currentDatabaseCredential);
var title = success ? "Test Connessione - Successo" : "Test Connessione - Errore";
await JSRuntime.InvokeVoidAsync("alert", $"{title}\\n\\n{message}");
}
catch (Exception ex)
{
await JSRuntime.InvokeVoidAsync("alert", $"Errore nel test della connessione: {ex.Message}");
}
finally
{
testingConnection = false;
}
}
```
**Validazioni Implementate**:
1. **ODBC DSN Mode**:
- ✅ Nome credenziale (obbligatorio)
- ✅ DSN selezionato (obbligatorio)
- ️ Username/Password (opzionali - possono essere nel DSN)
2. **ODBC Custom Mode**:
- ✅ Nome credenziale (obbligatorio)
- ✅ Driver ODBC (obbligatorio)
- ✅ Server/Host (obbligatorio)
- ️ Porta, Database, Username, Password (opzionali)
3. **Altri Database (SQL Server, MySQL, etc.)**:
- ✅ Nome credenziale (obbligatorio)
- ✅ Host (obbligatorio)
- ✅ Username (obbligatorio)
- ✅ Password (obbligatorio)
**Status**: Risolto
---
## 🔧 Altre Correzioni
### Inizializzazione AdditionalParameters
Aggiunto nel costruttore per evitare NullReferenceException:
```csharp
private async Task ShowAddDatabaseModal()
{
currentDatabaseCredential = new DatabaseCredential
{
DatabaseType = CredentialManager.Models.DatabaseType.SqlServer,
Port = 1433,
CommandTimeout = 30,
AdditionalParameters = new Dictionary<string, string>() // ✅ Aggiunto
};
// ...
}
```
---
## ✅ Test di Verifica
### Test 1: DSN Mode - Caricamento Automatico
1. Aprire "Aggiungi Database"
2. Selezionare tipo "ODBC"
3. ✅ Verificare che lista DSN sia popolata automaticamente
4. Selezionare un DSN
5. Inserire username/password (opzionale)
6. Click "Testa Connessione"
7. ✅ Dovrebbe connettersi senza errori di validazione
### Test 2: DSN Mode - Solo Nome e DSN
1. Aprire "Aggiungi Database"
2. Selezionare tipo "ODBC"
3. Inserire solo Nome e selezionare DSN (no username/password)
4. Click "Testa Connessione"
5. ✅ Dovrebbe passare validazione e tentare connessione
### Test 3: Custom Mode - Validazione Driver
1. Aprire "Aggiungi Database"
2. Selezionare tipo "ODBC"
3. Selezionare "Connection String Personalizzata"
4. Inserire Nome, Host, Database
5. NON selezionare driver
6. Click "Testa Connessione"
7. ✅ Dovrebbe mostrare "Seleziona un driver ODBC"
### Test 4: Custom Mode - Validazione Host
1. Aprire "Aggiungi Database"
2. Selezionare tipo "ODBC"
3. Selezionare "Connection String Personalizzata"
4. Inserire Nome, selezionare Driver
5. NON inserire Host
6. Click "Testa Connessione"
7. ✅ Dovrebbe mostrare "Inserisci il server/host"
### Test 5: Altri Database - Validazione Standard
1. Aprire "Aggiungi Database"
2. Selezionare tipo "SQL Server"
3. Inserire solo Nome
4. Click "Testa Connessione"
5. ✅ Dovrebbe mostrare "Compila tutti i campi obbligatori (Host, Username, Password)"
---
## 📊 File Modificati
### `Data_Coupler/Pages/CredentialManagement.razor`
**Metodo Modificato**: `TestCurrentDatabaseConnection()` (righe ~952-1008)
- Aggiunta validazione condizionale per tipo database
- Logica separata per ODBC DSN mode vs Custom mode vs altri database
- Messaggi di errore specifici per ogni scenario
**Status Compilazione**: ✅ Riuscita (8 avvisi standard)
---
## 📝 Note Tecniche
### Flusso Validazione ODBC DSN Mode
```
Nome credenziale?
NO → ❌ "Il nome della credenziale è obbligatorio"
YES ↓
DatabaseType == ODBC?
NO → Validazione standard (Host, User, Pass)
YES ↓
OdbcMode == DSN?
NO → Validazione Custom (Driver, Host)
YES ↓
DSN selezionato?
NO → ❌ "Seleziona un DSN ODBC"
YES → ✅ Procedi con test connessione
```
### Flusso Validazione ODBC Custom Mode
```
Nome credenziale?
NO → ❌ "Il nome della credenziale è obbligatorio"
YES ↓
DatabaseType == ODBC?
NO → Validazione standard
YES ↓
OdbcMode == Custom?
NO → Validazione DSN
YES ↓
Driver presente in AdditionalParameters?
NO → ❌ "Seleziona un driver ODBC"
YES ↓
Host compilato?
NO → ❌ "Inserisci il server/host"
YES → ✅ Procedi con test connessione
```
---
**Data**: 2 Febbraio 2026
**Versione**: 1.0
**Framework**: .NET 9.0
**Status**: ✅ Completato e testato