Aggiornamento main #12
@@ -67,6 +67,19 @@ public partial class DataCoupler : ComponentBase
|
||||
|
||||
// ===== METODI DATABASE =====
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se la credenziale database selezionata è di tipo ODBC
|
||||
/// </summary>
|
||||
/// <returns>True se la credenziale è ODBC, altrimenti False</returns>
|
||||
protected bool IsOdbcConnection()
|
||||
{
|
||||
if (string.IsNullOrEmpty(selectedDatabaseCredential))
|
||||
return false;
|
||||
|
||||
var credential = databaseCredentials.FirstOrDefault(c => c.Name == selectedDatabaseCredential);
|
||||
return credential?.DatabaseType == DatabaseType.Odbc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gestisce il cambio di credenziale database selezionata
|
||||
/// </summary>
|
||||
@@ -74,6 +87,12 @@ public partial class DataCoupler : ComponentBase
|
||||
{
|
||||
selectedDatabaseCredential = e.Value?.ToString() ?? "";
|
||||
ResetDatabaseState();
|
||||
|
||||
// Se è una connessione ODBC, forza l'uso di query custom
|
||||
if (IsOdbcConnection())
|
||||
{
|
||||
useCustomQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -571,14 +590,15 @@ public partial class DataCoupler : ComponentBase
|
||||
/// </summary>
|
||||
protected async Task ValidateCustomQuery()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(customQuery) || currentDatabaseManager == null)
|
||||
if (string.IsNullOrWhiteSpace(customQuery))
|
||||
{
|
||||
isQueryValid = false;
|
||||
queryValidationMessage = "Query vuota o manager database non disponibile";
|
||||
queryValidationMessage = "Query vuota";
|
||||
return;
|
||||
}
|
||||
|
||||
isValidatingQuery = true;
|
||||
IDatabaseManager? tempManager = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -601,13 +621,30 @@ public partial class DataCoupler : ComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
// Per ODBC, crea un database manager temporaneo se non esiste
|
||||
var managerToUse = currentDatabaseManager;
|
||||
if (managerToUse == null && IsOdbcConnection())
|
||||
{
|
||||
Logger.LogInformation("Creando database manager temporaneo per validazione query ODBC");
|
||||
tempManager = await ConnectionFactory.CreateDatabaseManagerAsync(selectedDatabaseCredential);
|
||||
managerToUse = tempManager;
|
||||
}
|
||||
|
||||
// Se ancora non abbiamo un manager, errore
|
||||
if (managerToUse == null)
|
||||
{
|
||||
isQueryValid = false;
|
||||
queryValidationMessage = "Manager database non disponibile. Connettersi prima di validare la query.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Crea una query di test con sintassi appropriata per il tipo di database
|
||||
var testQuery = CreateLimitedQuery(cleanQuery, credential.DatabaseType, 1);
|
||||
|
||||
Logger.LogInformation("Validando query: {Query}", testQuery);
|
||||
|
||||
// Prova a eseguire la query per validarla
|
||||
var testResults = await currentDatabaseManager.ExecuteRawQueryAsync(testQuery);
|
||||
var testResults = await managerToUse.ExecuteRawQueryAsync(testQuery);
|
||||
|
||||
if (testResults != null && testResults.Any())
|
||||
{
|
||||
@@ -623,6 +660,13 @@ public partial class DataCoupler : ComponentBase
|
||||
TryAutoSelectKeyForQuery(queryColumns);
|
||||
|
||||
Logger.LogInformation("Query validata con successo: {ColumnCount} colonne", queryColumns.Count);
|
||||
|
||||
// Per ODBC, salva il manager se non era già presente
|
||||
if (IsOdbcConnection() && currentDatabaseManager == null && tempManager != null)
|
||||
{
|
||||
currentDatabaseManager = tempManager;
|
||||
tempManager = null; // Non distruggerlo nel finally
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -639,6 +683,13 @@ public partial class DataCoupler : ComponentBase
|
||||
finally
|
||||
{
|
||||
isValidatingQuery = false;
|
||||
|
||||
// Pulisci il manager temporaneo se non è stato salvato
|
||||
if (tempManager != null)
|
||||
{
|
||||
try { tempManager.Dispose(); } catch { /* Ignora errori di dispose */ }
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,19 +70,32 @@
|
||||
|
||||
@if (!string.IsNullOrEmpty(selectedDatabaseCredential))
|
||||
{
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-success btn-sm" @onclick="ConnectToDatabase" disabled="@isConnectingDatabase">
|
||||
@if (isConnectingDatabase)
|
||||
<!-- Per ODBC: mostra messaggio esplicativo, niente discovery -->
|
||||
@if (IsOdbcConnection())
|
||||
{
|
||||
<div class="alert alert-info" role="alert">
|
||||
<i class="oi oi-info"></i> <strong>Connessione ODBC rilevata</strong><br>
|
||||
Per le connessioni ODBC, il discovery automatico delle tabelle non è disponibile.<br>
|
||||
Procedi direttamente con l'inserimento di una <strong>query SQL custom</strong> nella sezione sottostante.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Per database standard: mostra pulsante di connessione -->
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-success btn-sm" @onclick="ConnectToDatabase" disabled="@isConnectingDatabase">
|
||||
@if (isConnectingDatabase)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
}
|
||||
<i class="fas fa-plug"></i> Connetti e Scopri Schema
|
||||
</button>
|
||||
@if (isDatabaseConnected)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
<span class="badge bg-success ms-2">Connesso</span>
|
||||
}
|
||||
<i class="fas fa-plug"></i> Connetti e Scopri Schema
|
||||
</button>
|
||||
@if (isDatabaseConnected)
|
||||
{
|
||||
<span class="badge bg-success ms-2">Connesso</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
} @if (!string.IsNullOrEmpty(databaseErrorMessage))
|
||||
{
|
||||
<div class="alert alert-danger" role="alert">
|
||||
@@ -90,8 +103,126 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Lista Tabelle -->
|
||||
@if (isDatabaseConnected)
|
||||
<!-- Per ODBC: mostra direttamente la sezione Query Custom -->
|
||||
@if (IsOdbcConnection())
|
||||
{
|
||||
<!-- Sezione Query Custom per ODBC -->
|
||||
<div class="mb-3">
|
||||
<h6>Query SQL Custom:</h6>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Scrivi la tua query SELECT:</label>
|
||||
<textarea class="form-control" rows="6" placeholder="SELECT * FROM your_table WHERE condition..."
|
||||
@bind="customQuery" @bind:event="oninput"></textarea>
|
||||
<div class="mt-2">
|
||||
<div class="alert alert-warning d-flex align-items-start" role="alert">
|
||||
<i class="fas fa-shield-alt me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>Controlli di Sicurezza Attivi:</strong><br>
|
||||
<small>
|
||||
• Solo query <strong>SELECT</strong> sono permesse<br>
|
||||
• Operazioni come INSERT, UPDATE, DELETE, DROP sono bloccate<br>
|
||||
• Query multiple separate da ; non sono consentite<br>
|
||||
• La query verrà automaticamente ottimizzata per il trasferimento dati
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<button class="btn btn-primary btn-sm me-2" @onclick="ValidateCustomQuery"
|
||||
disabled="@(isValidatingQuery || string.IsNullOrWhiteSpace(customQuery))">
|
||||
@if (isValidatingQuery)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
}
|
||||
<i class="fas fa-check-circle"></i> Valida Query
|
||||
</button>
|
||||
|
||||
@if (isQueryValid)
|
||||
{
|
||||
<button class="btn btn-info btn-sm me-2" @onclick="LoadQueryPreview"
|
||||
disabled="@isLoadingPreview">
|
||||
@if (isLoadingPreview)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
||||
}
|
||||
<i class="fas fa-eye"></i> Anteprima Risultati
|
||||
</button>
|
||||
|
||||
@if (showQueryPreview)
|
||||
{
|
||||
<button class="btn btn-outline-secondary btn-sm" @onclick="HideQueryPreview">
|
||||
<i class="fas fa-eye-slash"></i> Nascondi Anteprima
|
||||
</button>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(queryValidationMessage))
|
||||
{
|
||||
@if (isQueryValid)
|
||||
{
|
||||
<div class="alert alert-success" role="alert">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
@queryValidationMessage
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
@queryValidationMessage
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<!-- Anteprima risultati query -->
|
||||
@if (showQueryPreview && queryPreviewData.Any())
|
||||
{
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-table"></i> Anteprima Risultati Query
|
||||
<span class="badge bg-info ms-2">@queryPreviewData.Count righe</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive" style="max-height: 400px;">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead class="table-dark sticky-top">
|
||||
<tr>
|
||||
@if (queryColumns.Any())
|
||||
{
|
||||
@foreach (var col in queryColumns)
|
||||
{
|
||||
<th>@col</th>
|
||||
}
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var row in queryPreviewData)
|
||||
{
|
||||
<tr>
|
||||
@foreach (var col in queryColumns)
|
||||
{
|
||||
<td>@row.GetValueOrDefault(col)?.ToString()</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Lista Tabelle (solo per database NON ODBC) -->
|
||||
@if (isDatabaseConnected && !IsOdbcConnection())
|
||||
{
|
||||
<!-- Selezione modalità: Tabelle o Query Custom -->
|
||||
<div class="mb-3">
|
||||
|
||||
Reference in New Issue
Block a user