Files
Data-Coupler/ODBC_UI_CORRECTIONS.md
T
Alessio Dal Santo 01f78466df [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.
2026-02-02 18:24:44 +01:00

13 KiB

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:
private async Task ShowAddDatabaseModal()
{
    // ... inizializzazione ...
    showDatabaseModal = true;
    
    // Carica automaticamente se ODBC è selezionato
    if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc)
    {
        await LoadOdbcData();
    }
}
  1. EditDatabaseCredential() - Modificato per essere asincrono, caricare dati ODBC e ripristinare il driver selezionato:
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;
}
  1. Button Bindings - Aggiornati per chiamate asincrone:
<!-- 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:

@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:

<!-- 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():

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():

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():

private void UpdateOdbcParameterValue(string key, string value)
{
    if (currentDatabaseCredential.AdditionalParameters == null)
        return;
        
    if (currentDatabaseCredential.AdditionalParameters.ContainsKey(key))
    {
        currentDatabaseCredential.AdditionalParameters[key] = value;
        StateHasChanged();
    }
}

RemoveOdbcParameter():

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:

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

  • Aprire "Aggiungi Database"
  • Selezionare tipo "ODBC"
  • Verificare che liste DSN e driver siano popolate automaticamente
  • Nessun click su "Aggiorna Lista" necessario

Test 2: Edit Credenziale ODBC

  • Creare credenziale ODBC con driver e parametri custom
  • Salvare
  • Riaprire in modifica
  • Verificare che driver e parametri custom siano ripristinati

Test 3: Nessuna Ridondanza

  • Aprire modal con ODBC selezionato
  • Verificare UNA SOLA sezione username/password (nella config ODBC)
  • Cambiare a SQL Server
  • Verificare che username/password appaiano nella sezione standard

Test 4: Parametri Personalizzati

  • Modalità Custom ODBC
  • Click "Aggiungi" in Parametri Personalizzati
  • Inserire nome (es. "TrustServerCertificate") e valore ("yes")
  • Aggiungere altro parametro (es. "Encrypt=no")
  • Verificare preview connection string includa entrambi
  • Salvare credenziale
  • 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)