Страсти по делегатам
Обычно можно сделать так
это правильный ответ
но чтобы сохранить интригу, что изменится от того, если ЛИНК написать так(как у нас внегласно заведено)?
вместо ! напишем == false
var personsNotInEvent = dbContext.Persons .Where(p => dbContext.Events.Any(e => e.PersonId == p.PersonId) == false) .ToList();
Только у вас подзапрос будет выполняться на каждое вхождение основного запроса (саечка за неоптимальность )нука расскажи, почему ты так решил?
потому что делегат в where выполняется для каждого вхождения
var personsNotInEvent = dbContext.Persons .Where(p => dbContext.Events.Any(e => e.PersonId == p.PersonId) == false) .ToList();
Вы начитались "каверзных вопросов", где требуют знать все тонкости, как построитель и оптимизатор запросов внутри преобразует те или иные условия в фильтрующих делегатах?
весь этот LINQ конвертируется в один SQL-запрос
А если я использую в
dbContext.Events.Any(e => e.PersonId == p.PersonId)
какую-нибудь внешнюю по отношению к запросу коллекцию, типа
myCollection.Contains(item => item.PersonId == p.PersonId)
то вся коллекция myCollection будет передана в запрос?
Linqpad даёт следующее
List<LiveResult> (2 items)••• | ||||||||
Case | ResultsGraph | Mean | Min | Max | Range | AllocatedBytesΞΞ | OperationsΞΞ | Phase |
---|---|---|---|---|---|---|---|---|
BenchmarkDemoWhereNot | 2.72 μs | 2.67 μs | 2.75 μs | 3% | 2'200 | 3'145'728 | Complete | |
BenchmarkDemoWhereFalse | 2.79 μs | 2.70 μs | 2.98 μs | 10% | 2'240 | 7'077'888 | Complete |
какую-нибудь внешнюю по отношению к запросу коллекцию, типа
myCollection.Contains(item => item.PersonId == p.PersonId)
то вся коллекция myCollection будет передана в запрос?
Это имхо вообще не переведётся в SQL.
А вот если у тебя будет коллекция простых integer, то да, все значения передадутся в запрос.
А ты как думал: на каждый элемент по запросу в БД?))
Там локальная SQLite, хотя обновил до нет 8.0
Немного изменил под существующие таблицы
#load "BenchmarkDotNet" void Main() { } [Benchmark] public void BenchmarkDemoWhereNot() { var context = this; var personsNotInEvent = context.Artists .Where (p => !Albums.Any(e => e.ArtistId == p.ArtistId)); } [Benchmark] public void BenchmarkDemoWhereFalse() { var context = this; var personsNotInEvent = context.Artists .Where (p => Albums.Any(e => e.ArtistId == p.ArtistId) == false); }
А ты как думал: на каждый элемент по запросу в БД?))
А я не помню, как оно работает. Вроде, если сущности из одного контекста, то он пытается это в один запрос сделать. Но в моём примере по ссылке либо джойны придлагают, либо сначала сделать один запрос, превратить его в просто коллекцию объектов, а потом второй запрос с использованием этой коллекции.
И интересно было бы посмотреть сгенерированный SQL.
но проблемо, для этого linqpad и открывался
SELECT "a"."ArtistId", "a"."Name" FROM "Artist" AS "a" WHERE NOT EXISTS ( SELECT 1 FROM "Album" AS "a0" WHERE "a0"."ArtistId" = "a"."ArtistId")
ну и как, есть разница в скорости в SQL Lite?
на такой мелочевке данных то.
Отчего - это нужно изучать специально. Может и нет 8.0 починили