Почему следующий запрос linq to sql сгенерировал подзапрос? - PullRequest
10 голосов
/ 14 декабря 2009

Я сделал следующий запрос:

var list = from book in books
          where book.price > 50
          select book;

list = list.Take(50);

Я ожидаю, что выше будет генерировать что-то вроде:

SELECT top 50 id, title, price, author
FROM Books
WHERE price > 50

но генерирует:

SELECT
[Limit1].[C1] as [C1]
[Limit1].[id] as [Id], 
[Limit1].[title] as [title], 
[Limit1].[price] as [price], 
[Limit1].[author]
FROM (SELECT TOP (50) 
             [Extent1].[id] as as [Id], 
             [Extent1].[title] as [title], 
             [Extent1].[price] as [price], 
             [Extent1].[author] as [author]
      FROM Books as [Extent1]
      WHERE [Extent1].[price] > 50
     ) AS [Limit1]

Почему указанный выше запрос linq генерирует подзапрос и откуда берется C1?

Ответы [ 5 ]

2 голосов
/ 14 декабря 2009

Отказ от ответственности: Я никогда не использовал LINQ раньше ...

Я думаю, будет поддержка пейджинга? Я предполагаю, что у вас есть какой-то Take(50, 50) метод, который получает 50 записей, начиная с записи 50. Посмотрите на SQL, который генерирует запрос, и вы, вероятно, обнаружите, что он использует аналогичную структуру подзапроса, чтобы позволить ему возвращать любые 50 строк в запросе приблизительно за то время, когда он возвращает первые 50 строк.

В любом случае вложенный подзапрос не добавляет никаких издержек производительности, поскольку он автоматически оптимизируется во время компиляции плана выполнения.

1 голос
/ 14 декабря 2009

Вы все еще можете сделать его чище, как это:

var c = (from co in db.countries
                    where co.regionID == 5
                    select co).Take(50);

Это приведет к:

Table(country).Where(co => (co.regionID = Convert(5))).Take(50)

Эквивалентно:

SELECT TOP (50) [t0].[countryID], [t0].[regionID], [t0].[countryName], [t0].[code]
FROM [dbo].[countries] AS [t0]
WHERE [t0].[regionID] = 5

РЕДАКТИРОВАТЬ: Комментарии, это не обязательно, потому что с отдельным Take (), вы все равно можете использовать его так:

var c = (from co in db.countries
                     where co.regionID == 5
                     select co);
            var l = c.Take(50).ToList();

И Результат будет таким же, как и раньше.

SELECT TOP (50) [t0].[countryID], [t0].[regionID], [t0].[countryName], [t0].[code]
FROM [dbo].[countries] AS [t0]
WHERE [t0].[regionID] = @p0

Тот факт, что вы написали IQueryable = IQueryable.Take(50), является сложной частью здесь.

0 голосов
/ 14 декабря 2009
  1. Я согласен с @Justin Swartsel. Там не было никакой ошибки, так что это в значительной степени академический вопрос.
  2. Linq-to-SQL пытается генерировать SQL, который эффективно запускает (что и было в вашем случае).
    1. Но он не прилагает никаких усилий для генерации обычного SQL, который может создать человек.
  3. Реализаторы Linq-to-SQL, вероятно, использовали шаблон построителя для генерации SQL.
    1. Если это так, было бы проще добавить подстроку (или подзапрос в данном случае), чем было бы откатить назад и вставить фрагмент «TOP x» в предложение SELECT.
0 голосов
/ 14 декабря 2009

Разве это не случай, когда первый запрос возвращает общее количество строк, а второй извлекает подмножество строк на основе вызова метода .Take ()?

0 голосов
/ 14 декабря 2009

Подзапрос генерируется для проекционных целей, он имеет больше смысла, когда вы выбираете из нескольких таблиц в один анонимный объект, тогда внешний запрос используется для сбора результатов.

Попробуйте, что происходит с чем-то вроде этого:

from book in books
where price > 50
select new 
{
  Title = book.title,
  Chapters = from chapter in book.Chapters
             select chapter.Title
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...