feat: Implementa gestione intelligente della chiave sorgente con rilevamento PK

- Aggiunge rilevamento automatico Primary Key per connessioni database
- Rimuove completamente il fallback automatico per lato sorgente
- Implementa selezione manuale obbligatoria per file e sorgenti non-DB
- Migliora UI con suggerimenti intelligenti e feedback visivo
- Aggiunge validazione multi-livello (UI, pre-transfer, runtime)
- Introduce metodo GetPrimaryKeyFieldAsync in IDatabaseManager
- Modifica GenerateSourceKey per richiedere sempre campo specifico
- Implementa controllo IsTransferButtonEnabled per validazione form

Breaking changes:
- La generazione automatica delle chiavi sorgente è stata rimossa
- Il campo chiave sorgente è ora obbligatorio quando si usa il sistema associazioni

Fixes: Risolve problema di discovery schema vuoto con selezione database
This commit is contained in:
2025-06-28 02:05:59 +02:00
parent 207d6fc845
commit 51c61eabf7
29 changed files with 2748 additions and 104 deletions
@@ -56,4 +56,14 @@ public interface IDataConnectionCredentialService
Task<(bool Success, string Message)> TestSapB1ConnectionAsync(SapB1ServiceLayerCredential credential);
Task<(bool Success, string Message)> TestSalesforceConnectionAsync(string credentialName);
Task<(bool Success, string Message)> TestSalesforceConnectionAsync(SalesforceCredential credential);
// Record associations
Task<int> SaveRecordAssociationAsync(RecordAssociation association);
Task<RecordAssociation?> FindRecordAssociationAsync(string sourceName, string sourceKey, string destinationEntity);
Task<List<RecordAssociation>> GetRecordAssociationsBySourceAsync(string sourceName, string sourceType);
Task<List<RecordAssociation>> GetRecordAssociationsByDestinationAsync(string destinationEntity, string restCredentialName);
Task<List<RecordAssociation>> GetAllActiveRecordAssociationsAsync();
Task<bool> UpdateRecordAssociationAsync(RecordAssociation association);
Task<bool> DeactivateRecordAssociationAsync(int id);
Task<bool> DeleteRecordAssociationAsync(int id);
}
@@ -38,6 +38,9 @@ public static class ServiceCollectionExtensions
// Aggiungi i servizi base di CredentialManager
services.AddCredentialManager(databasePath);
// Aggiungi il servizio di gestione associazioni record
services.AddScoped<IRecordAssociationService, RecordAssociationService>();
// Aggiungi il servizio di integrazione DataConnection
services.AddScoped<IDataConnectionCredentialService, DataConnectionCredentialService>();
@@ -15,13 +15,16 @@ namespace DataConnection.CredentialManagement.Services;
public class DataConnectionCredentialService : IDataConnectionCredentialService
{
private readonly ICredentialService _credentialService;
private readonly IRecordAssociationService _recordAssociationService;
private readonly ILogger<DataConnectionCredentialService> _logger;
public DataConnectionCredentialService(
ICredentialService credentialService,
IRecordAssociationService recordAssociationService,
ILogger<DataConnectionCredentialService> logger)
{
_credentialService = credentialService;
_recordAssociationService = recordAssociationService;
_logger = logger;
}
@@ -855,4 +858,48 @@ public class DataConnectionCredentialService : IDataConnectionCredentialService
}
#endregion
#region Record Associations
public async Task<int> SaveRecordAssociationAsync(RecordAssociation association)
{
return await _recordAssociationService.SaveAssociationAsync(association);
}
public async Task<RecordAssociation?> FindRecordAssociationAsync(string sourceName, string sourceKey, string destinationEntity)
{
return await _recordAssociationService.FindAssociationAsync(sourceName, sourceKey, destinationEntity);
}
public async Task<List<RecordAssociation>> GetRecordAssociationsBySourceAsync(string sourceName, string sourceType)
{
return await _recordAssociationService.GetAssociationsBySourceAsync(sourceName, sourceType);
}
public async Task<List<RecordAssociation>> GetRecordAssociationsByDestinationAsync(string destinationEntity, string restCredentialName)
{
return await _recordAssociationService.GetAssociationsByDestinationAsync(destinationEntity, restCredentialName);
}
public async Task<List<RecordAssociation>> GetAllActiveRecordAssociationsAsync()
{
return await _recordAssociationService.GetAllActiveAssociationsAsync();
}
public async Task<bool> UpdateRecordAssociationAsync(RecordAssociation association)
{
return await _recordAssociationService.UpdateAssociationAsync(association);
}
public async Task<bool> DeactivateRecordAssociationAsync(int id)
{
return await _recordAssociationService.DeactivateAssociationAsync(id);
}
public async Task<bool> DeleteRecordAssociationAsync(int id)
{
return await _recordAssociationService.DeleteAssociationAsync(id);
}
#endregion
}