Ho seguito generable queryable (che può già avere selezioni applicate):
IQueryable<TEntity> queryable = DBSet<TEntity>.AsQueryable();
Poi c'è la classe Provider
che assomiglia a questo:
public class Provider<TEntity>
{
public Expression<Func<TEntity, bool>> Condition { get; set; }
[...]
}
La Condition
può essere definita per istanza nel seguente modo:
Condition = entity => entity.Id == 3;
Ora voglio selezionare tutte le istanze Provider
che hanno una Condition
che è soddisfatta almeno da una entità del DBSet
:
List<Provider> providers = [...];
var matchingProviders = providers.Where(provider => queryable.Any(provider.Condition))
Il problema con questo: sto iniziando una query per ogni istanza di Provider
nell'elenco. Preferirei usare una singola query per ottenere lo stesso risultato. Questo argomento è particolarmente importante a causa di prestazioni discutibili. Come posso ottenere gli stessi risultati con una singola query e migliorare le prestazioni utilizzando le istruzioni Linq
o le Expression Trees
?
Sfida interessante L'unico modo che vedo è di creare dinamicamente UNION ALL
query come questa:
SELECT TOP 1 0 FROM Table WHERE Condition[0]
UNION ALL
SELECT TOP 1 1 FROM Table WHERE Condition[1]
...
UNION ALL
SELECT TOP 1 N-1 FROM Table WHERE Condition[N-1]
e quindi utilizzare i numeri restituiti come indice per ottenere i provider corrispondenti.
Qualcosa come questo:
var parameter = Expression.Parameter(typeof(TEntity), "e");
var indexQuery = providers
.Select((provider, index) => queryable
.Where(provider.Condition)
.Take(1)
.Select(Expression.Lambda<Func<TEntity, int>>(Expression.Constant(index), parameter)))
.Aggregate(Queryable.Concat);
var indexes = indexQuery.ToList();
var matchingProviders = indexes.Select(index => providers[index]);
Si noti che avrei potuto creare la query senza utilizzare la classe Expression
sostituendo la Select
precedente con
.Select(_ => index)
ma ciò introdurrebbe un parametro di query SQL non necessario per ogni indice.