#c# #sql #sql-server #entity-framework #linq
Вопрос:
Я пытаюсь реализовать SQL-запрос с помощью LINQ (и EF Core 2.2.2), но я застрял.
SQL-запрос является:
SELECT DISTINCT([client].[Id]), [client].[Name]
FROM [Clients] AS [client]
LEFT JOIN [Documents] as [doc] ON [client].[Id] = [doc].[ClientId]
WHERE client.Name LIKE N'%test%' OR
doc.Name LIKE N'%test%' OR
ORDER BY client.Id DESC
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY
и я начал писать запрос с помощью LINQ:
from client in context.Set<Client>()
from doc in client.Documents.DefaultIfEmpty()
where client.Name.Contains("test")
or doc.Name.Contains("test")
group client by client.Id into c // this should act as 'distinct'
select c.First()
Но теперь я застрял с тем , как добавить ORDER BY
, OFFSET
и FETCH
.
Я пытался написать что-то вроде этого:
(
from client in context.Set<Client>()
from doc in client.Documents.DefaultIfEmpty()
where client.Name.Contains("test")
or doc.Name.Contains("test")
group client by client.Id into c // this should act as 'distinct'
select c.First()
)
.OrderByDescending(c => c.Id) // this is still working on IQueryable
.Skip(10)
.Take(10)
.ToListAsync();
И он вернул правильные результаты, но когда я посмотрел на профилировщик SQL, запрос вообще не включал упорядочение и пропуск (это было сделано на прикладном уровне для всего набора, возвращенного запросом).
Есть ли способ сделать это с помощью LINQ, или мне нужно использовать обычный SQL в своей кодовой базе?
Комментарии:
1. Что произойдет, если вы напишете это в синтаксисе метода вместо синтаксиса запроса? Кстати, вам может показаться интересным разбиение набора ключей на страницы, это гораздо эффективнее, чем разбиение на страницы наборов строк
2. Какой ORM вы используете? Ядро EF?
3. Можете ли вы использовать любой другой ORM? Например, linq2db? Он генерирует именно те запросы, которые вы хотите.
4. @AlexanderPetrov: привет, да, EF Core, забыл упомянуть об этом. Ну, это существующий устаревший проект, поэтому на данный момент я считаю, что было бы более разумно писать SQL вручную, чем изменять ORM.
5. Да, на вопросы о производительности, как известно, трудно ответить 🙂 Жаль, что запрос LINQ работает намного лучше,
Any
потому что вы можете просто складывать предикаты, и в этом нет необходимостиDistinct
. В большинстве случаев анализ запросов с помощью советника по настройке SQL Server позволит использовать EXISTS просто отлично, но да, мы не можем сделать это за вас.
Ответ №1:
Различение невозможно с помощью синтаксиса запроса, поэтому просто объедините их:
var query =
from client in _clientService.Query()
from doc in client.Documents.DefaultIfEmpty()
where client.Name.Contains("test") || doc.Name.Contains("test")
select new { client.Id, client.Name };
var result = await query
.Distinct()
.OrderBy(x => x.Id)
.Skip(10)
.Take(10)
.ToListAsync();