Stiamo convertendo da LINQ a SQL in Entity Framework Core 2.2 e stiamo scoprendo che la traduzione delle operazioni Contains non diventa clausole IN in SQL Server. Quello che sta succedendo è che EFCore sta ritirando tutti i dati usando le altre condizioni e poi li sta filtrando localmente. Questo non è accettabile. Possiamo usare EF.Functions.Contains ma questo ci richiede di abilitare la ricerca full-text in SQL Server, che è over kill.
Qualche idea su come ottenere un'istruzione come la seguente da tradurre in una clausola IN in SQL Server?
var myValues = new [] { 1, 2, 3, 4, 5 };
var qry = _context.Table.Where(t => myValues.Contains(t.TableProperty));
Ok, forse ho semplificato troppo il codice per renderlo semplice per la domanda. Il codice attuale è simile a:
voterQuery = voterQuery.Where(v => voterFilter.VoterStatus.Select(p => p.Value).Contains(v.VotStatus.ToString()));
Ciò che sta accadendo nel nostro codice è che stiamo creando un IQueriable dalle selezioni dell'utente su una schermata di filtro. voterFilters contiene una raccolta di questi criteri di selezione. VoterStatus è uno dei criteri di selezione che è un elenco, che provengono da un controllo CheckedListItems di un winforms. La selezione di p.Value restituisce un Elenco di stringhe. Ho provato a proiettare l'elenco di stringhe su un array, con gli stessi risultati della clausola IN non creata o di una query del server. Forse, EFCore non consente l'utilizzo delle stringhe per i valori della clausola IN. Qualsiasi approfondimento sarebbe apprezzato.
Attualmente (a partire dalla v2.2.3), EF Core richiede che l'espressione utilizzata per Contains
sia una semplice variabile IEnumerable<T>
(senza operatori LINQ) in cui T
è di tipo primitivo.
Ciò significa che è necessario spostare voterFilter.VoterStatus.Select(p => p.Value)
in una variabile all'esterno dell'albero delle espressioni di query e utilizzare quella variabile all'interno:
var voterStatusFilter = voterFilter.VoterStatus.Select(p => p.Value);
voterQuery = voterQuery.Where(v => voteStatusFilter.Contains(v.VotStatus.ToString()));