Estamos usando linq2db . Acho que, ao criar uma consulta SQL, ela enumerará duas vezes ids
, porque ids
é IEnumerable<T>
. Estou certo de que a enumeração disso ids
será duas vezes e a consulta SQL será executada uma vez?
Não tenho certeza de como posso testá-lo e tentar saber se ele enumera duas vezes. Por favor, diga-me quantas vezes ids
serão enumeradas.
Depois de ler esta resposta (talvez eu tenha entendido a resposta incorretamente), acredito que a consulta SQL será executada uma vez e ids
será enumerada duas vezes?
[HttpGet]
[Route("persons")]
public async Task<IActionResult> GetAvailableAsync(IEnumerable<long> ids)
{
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();
return await query.ToListAsync()
}
Como isso é
IQueryable<T>
, não podemos dizer quantas vezes ele será executado.Queryable
expressões são tipicamente inspecionadas (noExpression
nível -tree) e reescritas - neste caso, muito provavelmente em SQL. Não sabemos os detalhes internos dessa operação de reescrita, então não podemos dizer quantas vezes ela avaliaids
- ela pode reconhecer a repetição e escrever isso como um único parâmetro (ou conjunto de parâmetros) para ambos os testes.Para descobrir quantas vezes ele está sendo iterado no momento , você pode escrever um enumerável personalizado e literalmente contar as chamadas para ele
GetEnumerator()
- no entanto, este é um detalhe de implementação e pode mudar.Se isso estivesse sendo avaliado como escrito, por exemplo via
.AsEnumerable()
, então: ele seria enumerado duas vezes (embora observe que tambémContains
pode fazer testes de tipo internamente, então ele não é realmente tratado comoIEnumerable<T>
internamente, se for um tipo bem conhecido; você pode ver isso aqui , por exemplo, onde ele usaICollection<T>.Contains
quando disponível).Se for importante quantas vezes ele é iterado: itere você mesmo uma vez, por exemplo, via
ToArray()
, e use esse instantâneo na sua consulta LINQ.Resumo: o aviso é válido.