Peço desculpas se essa pergunta for boba, mas estou ansioso para saber a resposta.
Estamos usando linq2db . Acredito que este IQueryable será executado uma vez no banco de dados. Mas não tenho certeza se é verdade por causa do aviso do Resharper que diz Possible Multiple enumeration
.
Minha consulta linq2db se parece com isso:
IEnumerable ids = Enumerable.Range(1, 10)
.Select(x => {Console.WriteLine(x); return x;});
IQueryable<PersonDto> query =
from person in dbContext.GetTable<DbPerson>()
where ids.Contains(person.Id) // here warning `Possible Multiple enumeration`
|| ids.Contains(person.DepartmentId) // here warning `Possible Multiple
// enumeration`
select
new PersonDto
{
Name = person.Name,
Id = person.Id,
DepartmentId = person.DepartmentId
}).Distinct();
await query.ToListAsync()
Eu sei que isso pode ser facilmente corrigido chamando .ToList()
. Mas eu só quero saber se é verdade que query
será enviado ao banco de dados 20 vezes? (por causa de Enumerable.Range(1, 10)
and ids
é usado duas vezes na where
condição)
Primeiro, o Linq2DB não está relacionado ao EF Core, é um ORM totalmente diferente.
Segundo, não haverá execuções múltiplas. O aviso do Resharper não se refere a execuções múltiplas de consultas SQL, ele se refere a iterações múltiplas do
ids
IEnumerable e está correto.Em vez disso, use isto:
ou
non-materialized parameters
não é um conceito EF, Linq2DB ou SQL. Os provedores EF Core ou Linq2DB convertem aIEnumerable<T>.Contains(someProp)
cláusula para a condição SQLprop in (@value1, @value2, ....)
. Quando isso acontece, o provedor tem que iterar sobre todos os valores. Embora isso não custe nada com uma lista ou array, ele força a reavaliação de quaisquer enumeráveis.Você não ganha nada usando um
IEnumerable<T>
, muito menos um typelessIEnumerable
. Você pode até causar boxing extra, pois os inteiros gerados são boxeados em objetos.No EF você pode obter o SQL gerado se usar o ToQueryString , por exemplo:
No Linq2DB, acho que você pode simplesmente usar
ToString()
, mas ainda não encontrei uma referência. Então, tente isto para ver o que você obtém:Em geral, quando o R# informa sobre esse aviso, isso significa que você está iterando a mesma coleção de itens várias vezes. Isso pode ser aceitável às vezes, por exemplo, quando sua coleção já está materializada em um array ou um
List<T>
. No entanto, quando sua coleção é umIQueryable<T>
, você está realizando a consulta novamente sempre que chamarIEnumerator.MoveNext()
- o que é feito implicitamente, por exemplo, chamandoFirst
, ouforeach
no referido queryable.No seu caso, o aviso vem de
IEnumerable ids = Enumerable.Range(1, 10) .Select(x => {Console.WriteLine(x); return x;});
, que não é uma coleção materializada. Então, o melhor seria chamarToArray
ouToList
nele e o aviso desaparece.Por outro lado, como essa coleção é bem pequena e não depende de nenhuma dependência externa (potencialmente pesada), você pode ignorar o aviso.
Btw.: Espero que sua
ids
variável -seja apenas para fins de teste. Você deve geralmente evitar expressões linq que tenham efeitos colaterais comoConsole.WriteLine
. Embora funcione, de alguma forma contradiz o propósito do LINQ que é sobre consultar , não sobre modificar . Melhor usar um loop classig nesses casos.