# Salesforce Batch Extraction - Miglioramenti Implementati ## 📋 Panoramica Sono stati implementati significativi miglioramenti al `SalesforceServiceClient` per ottimizzare l'estrazione degli oggetti REST utilizzando operazioni batch e parallel processing. Queste modifiche migliorano drasticamente le performance quando si lavora con grandi volumi di dati. ## 🚀 Nuove Funzionalità Implementate ### 1. **Batch Query Execution** #### `BatchExecuteQueriesAsync` - **Scopo**: Esegue multiple query SOQL in parallelo utilizzando le API Composite di Salesforce - **Limite**: Max 25 operazioni per richiesta composite (limite Salesforce) - **Parallelizzazione**: Processa automaticamente i batch in parallelo per massimizzare il throughput - **Utilizzo**: ```csharp var queries = new List { "SELECT Id, Name FROM Account WHERE Type = 'Customer'", "SELECT Id, FirstName, LastName FROM Contact WHERE Department = 'Sales'" }; var results = await salesforceClient.BatchExecuteQueriesAsync(queries, cancellationToken); ``` ### 2. **Batch Entity Search** #### `BatchFindEntitiesByKeysAsync` - **Scopo**: Cerca múltiple entità usando diverse combinazioni di chiavi in una singola operazione batch - **Ottimizzazione**: Raggruppa le ricerche per ridurre il numero di chiamate API - **Utilizzo**: ```csharp var keyFieldsList = new List> { new() { {"Email", "john@example.com"} }, new() { {"Email", "jane@example.com"} }, new() { {"Phone", "+1234567890"} } }; var results = await salesforceClient.BatchFindEntitiesByKeysAsync("Contact", keyFieldsList, cancellationToken); ``` #### `BatchGetEntitiesByIdsAsync` - **Scopo**: Recupera múltiple entità tramite i loro ID utilizzando query batch con clausole IN - **Ottimizzazione**: Max 200 ID per query per evitare limiti URL, ma processa migliaia di ID in parallelo - **Utilizzo**: ```csharp var entityIds = new List { "001XX000004TmiQYAS", "001XX000004TmiRYAS" }; var fieldsToSelect = new List { "Id", "Name", "Type", "BillingCity" }; var entities = await salesforceClient.BatchGetEntitiesByIdsAsync("Account", entityIds, fieldsToSelect, cancellationToken); ``` ### 3. **Advanced Extraction Methods** #### `ExtractAllEntitiesAsync` - **Scopo**: Estrae tutti i record di un'entità utilizzando paginazione automatica - **Features**: - Paginazione trasparente usando `nextRecordsUrl` - Supporto per filtri WHERE personalizzati - Limite massimo record configurabile - Auto-discovery dei campi se non specificati - **Utilizzo**: ```csharp var fieldsToSelect = new List { "Id", "Name", "Type", "CreatedDate" }; var whereClause = "Type = 'Customer' AND CreatedDate >= 2024-01-01T00:00:00Z"; var allAccounts = await salesforceClient.ExtractAllEntitiesAsync("Account", fieldsToSelect, whereClause, maxRecords: 5000, cancellationToken); ``` #### `ExtractEntitiesParallelAsync` - **Scopo**: Estrae entità utilizzando múltiple query parallele con criteri diversi - **Use Case**: Ideale per dividere grandi dataset per data, tipo, o altri criteri - **Deduplicazione**: Rimuove automaticamente i duplicati basandosi sul campo Id - **Utilizzo**: ```csharp var whereClauses = new List { "CreatedDate >= 2024-01-01T00:00:00Z AND CreatedDate < 2024-02-01T00:00:00Z", "CreatedDate >= 2024-02-01T00:00:00Z AND CreatedDate < 2024-03-01T00:00:00Z", "CreatedDate >= 2024-03-01T00:00:00Z AND CreatedDate < 2024-04-01T00:00:00Z" }; var allData = await salesforceClient.ExtractEntitiesParallelAsync("Opportunity", fieldsToSelect, whereClauses, cancellationToken: cancellationToken); ``` ### 4. **Utility Methods** #### `CreateDateBasedWhereClauses` - **Scopo**: Helper per creare automaticamente clausole WHERE basate su intervalli di date - **Configurabile**: Dimensione del chunk (default: 30 giorni), campo data da utilizzare - **Utilizzo**: ```csharp var startDate = DateTime.Parse("2024-01-01"); var endDate = DateTime.Parse("2024-12-31"); var whereClauses = salesforceClient.CreateDateBasedWhereClauses(startDate, endDate, "CreatedDate", chunkSizeInDays: 7); ``` #### `ExtractLargeDatasetAsync` - **Scopo**: Metodo intelligente che determina automaticamente la strategia ottimale - **Auto-Detection**: Controlla la dimensione del dataset e sceglie tra estrazione sequenziale o parallela - **Soglia**: >10,000 record = estrazione parallela con chunking per data - **Utilizzo**: ```csharp var largeDataset = await salesforceClient.ExtractLargeDatasetAsync("Case", fieldsToSelect, "Status = 'Open'", cancellationToken: cancellationToken); ``` #### `ExtractRecentlyModifiedAsync` - **Scopo**: Estrae entità modificate di recente (utile per sincronizzazioni incrementali) - **Configurabile**: Numero di ore indietro nel tempo (default: 24) - **Utilizzo**: ```csharp var recentContacts = await salesforceClient.ExtractRecentlyModifiedAsync("Contact", fieldsToSelect, hoursBack: 48, cancellationToken); ``` ## 📊 Miglioramenti delle Performance ### Prima delle modifiche: - ✅ Single query execution - ✅ Sequential processing - ❌ Multiple API calls per operazioni batch - ❌ No parallel processing - ❌ Manual pagination handling ### Dopo le modifiche: - ✅ **Batch query execution** (fino a 25 query contemporaneamente) - ✅ **Parallel processing** di múltiple batch - ✅ **Paginazione automatica** con `nextRecordsUrl` - ✅ **Auto-chunking** per grandi dataset - ✅ **Intelligent extraction strategy** selection - ✅ **Deduplicazione automatica** dei risultati - ✅ **Date-based parallel extraction** ### Risultati Attesi: - **🚀 Performance**: 10-25x più veloce per operazioni su grandi dataset - **📉 API Calls**: Riduzione del 60-90% delle chiamate API - **💾 Memory Efficiency**: Gestione ottimizzata della memoria con processing a chunck - **🔄 Reliability**: Gestione robusta degli errori con retry per singoli batch ## 🔧 Classi di Supporto Aggiunte ### `BatchQueryResult` ```csharp public class BatchQueryResult { public int QueryIndex { get; set; } // Indice della query originale public string Query { get; set; } // Query SOQL eseguita public bool Success { get; set; } // Successo operazione public string ErrorMessage { get; set; } // Messaggio di errore se fallita public List> Records { get; set; } // Risultati public int TotalSize { get; set; } // Numero totale di record public string? NextRecordsUrl { get; set; } // URL per paginazione } ``` ### Enhanced `SalesforceQueryResponse` ```csharp private class SalesforceQueryResponse { [JsonPropertyName("records")] public List> Records { get; set; } [JsonPropertyName("totalSize")] public int TotalSize { get; set; } [JsonPropertyName("done")] public bool Done { get; set; } [JsonPropertyName("nextRecordsUrl")] public string? NextRecordsUrl { get; set; } } ``` ## 📈 Scenari di Utilizzo ### 1. **Estrazione Completa di un'Entità** ```csharp // Estrae tutti i record Account con paginazione automatica var allAccounts = await salesforceClient.ExtractAllEntitiesAsync("Account"); ``` ### 2. **Estrazione di Grandi Dataset con Parallel Processing** ```csharp // Per dataset molto grandi, utilizza chunking automatico basato su date var largeDataset = await salesforceClient.ExtractLargeDatasetAsync("Case", maxRecords: 100000); ``` ### 3. **Sincronizzazione Incrementale** ```csharp // Estrae solo i record modificati nelle ultime 24 ore var recentlyModified = await salesforceClient.ExtractRecentlyModifiedAsync("Contact", hoursBack: 24); ``` ### 4. **Ricerca Batch di Multiple Entità** ```csharp var searchCriteria = new List> { new() { {"Email", "user1@company.com"} }, new() { {"Email", "user2@company.com"} }, // ... fino a centinaia di email }; var foundContacts = await salesforceClient.BatchFindEntitiesByKeysAsync("Contact", searchCriteria); ``` ### 5. **Estrazione Parallela per Intervalli Temporali** ```csharp var startDate = DateTime.Parse("2024-01-01"); var endDate = DateTime.Now; var whereClauses = salesforceClient.CreateDateBasedWhereClauses(startDate, endDate, "CreatedDate", 30); var historicalData = await salesforceClient.ExtractEntitiesParallelAsync("Opportunity", null, whereClauses); ``` ## 🛠️ Compatibilità e Migrazione - ✅ **Backward Compatible**: Tutti i metodi esistenti continuano a funzionare - ✅ **Enhanced Methods**: I metodi esistenti utilizzano automaticamente le nuove funzionalità batch quando possibile - ✅ **Optional Parameters**: Tutti i nuovi parametri sono opzionali con valori di default sensati - ✅ **Existing Interfaces**: Nessuna modifica alle interfacce pubbliche esistenti ## 📝 Note Tecniche ### Limiti Salesforce Rispettati: - **Composite API**: Max 25 sub-requests per richiesta - **SOQL IN Clause**: Max 200 valori per clausola IN - **URL Length**: Gestione automatica per evitare limiti URL - **API Rate Limits**: Distribuzione delle chiamate per rispettare i limiti ### Error Handling: - **Batch Failure Isolation**: Il fallimento di un batch non compromette gli altri - **Detailed Logging**: Logging completo per debugging e monitoraggio - **Graceful Degradation**: Fallback a metodi sequenziali in caso di errori ### Memory Management: - **Streaming Processing**: I dati vengono processati a chunk per evitare OutOfMemory - **Parallel Execution**: Limitazione della concorrenza per evitare sovraccarico - **Resource Cleanup**: Gestione appropriata delle risorse con using pattern --- **Data Implementazione**: Settembre 2024 **Versione**: 1.0 **Compatibile con**: Salesforce API v60.0+ **Framework**: .NET 9.0