Вопрос об основах LINQ to SQL - PullRequest
1 голос
/ 23 марта 2010

Я только начал изучать LINQ to SQL, и до сих пор меня впечатляет простота использования и хорошая производительность.

Раньше я думал, что при выполнении запросов LINQ, таких как

from Customer in DB.Customers where Customer.Age > 30 select Customer

LINQ получает всех клиентов из базы данных («SELECT * FROM Customers»), перемещает их в массив Customers и затем выполняет поиск в этом массиве с использованием методов .NET. Это очень неэффективно, что если в базе данных есть сотни тысяч клиентов? Выполнение таких больших запросов SELECT убило бы веб-приложение.

Теперь, когда я почувствовал, насколько быстрым является LINQ to SQL, я начинаю подозревать, что при выполнении только что написанного запроса LINQ каким-то образом преобразует его в строку SQL-запроса

SELECT * FROM Customers WHERE Age > 30

И только при необходимости он будет запускать запрос.

Итак, мой вопрос: я прав? И когда на самом деле выполняется запрос?

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

У меня есть 2 таблицы, одна из которых - Книги, другая - информация о том, сколько книг было продано в определенные дни. Моя цель - выбрать книги, у которых было как минимум 50 продаж в день за последние 10 дней. Это делается с помощью этого простого запроса:

from Book in DB.Books where (from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID).Contains(Book.ID) select Book

Дело в том, что мне нужно использовать проверочную часть в нескольких запросах, и я решил создать массив с идентификаторами всех популярных книг:

var popularBooksIDs = from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID;

НО, когда я пытаюсь сделать запрос сейчас:

from Book in DB.Books where popularBooksIDs.Contains(Book.ID) select Book

Это не работает! Вот почему я думаю, что мы не можем использовать тонкие сочетания клавиш в запросах LINQ to SQL, как мы не можем использовать их в реальном SQL. Мы должны создавать простые запросы, я прав?

Ответы [ 4 ]

3 голосов
/ 23 марта 2010

Вы правы. LINQ to SQL создает реальный SQL для получения ваших результатов.

Что касается ваших ярлыков, есть способы обойти ограничения:

var popularBooksIds = DB.Sales
    .Where(s => s.SalesAmount >= 50 
        && s.DateOfSale >= DateTime.Now.AddDays(-10))
    .Select(s => s.Id)
    .ToList();

// Actually should work. 
// Forces the table into memory and then uses LINQ to Objects for the query
var popularBooksSelect = DB.Books
    .ToList()
    .Where(b => popularBooksIds.Contains(b.Id));
1 голос
/ 25 марта 2010

http://damieng.com/blog/2008/07/30/linq-to-sql-log-to-debug-window-file-memory-or-multiple-writers

Это поможет вам увидеть, что и когда выполняются запросы. Кроме того, блог Дэмиенса полон других достоинств linq to sql.

Вы можете сгенерировать предложение EXISTS с помощью метода .Any. Я добился большего успеха, чем пытался генерировать предложения IN, потому что ему нравится извлекать все данные и передавать их обратно в качестве параметров в запрос

В linq to sql фрагменты выражений IQueryable можно объединить для создания одного запроса. Он будет пытаться сохранять все как IQueryable как можно дольше, прежде чем делать что-то, что не может быть выражено в SQL. Когда вы вызываете ToList, вы прямо просите его разрешить этот запрос в IEnumerable, хранящемся в памяти.

В большинстве случаев лучше не выбирать заранее идентификаторы книг. Храните фрагмент для популярных книг в одном месте кода и используйте его при необходимости для построения другого запроса. IQueryable - это просто дерево выражений, которое в какой-то другой момент преобразуется в SQL.

Если вы считаете, что ваше приложение будет работать лучше, храня популярные книги в другом месте (memcache или что-то еще), то вы можете рассмотреть возможность их извлечения заранее и проверки на это позже. Это будет означать, что каждый идентификатор книги будет передан в качестве параметра sproc и использован в предложении IN.

1 голос
/ 23 марта 2010

Платформа сущностей или запросы linq иногда могут быть сложными. Иногда вы удивляетесь эффективности сгенерированного SQL-запроса, а иногда этот запрос настолько сложен и неэффективен, что вы бьете себе в лоб.

Лучше всего, если у вас есть какие-либо подозрения по поводу запроса, запустите SQL Server Profiler в бэкэнде, который бы отслеживал все поступающие запросы. Таким образом, вы точно знаете, что передается на сервер SQL, и исправляете все неэффективности если нужно.

1 голос
/ 23 марта 2010

Да, запрос переводится в строку SQL, и базовый SQL может отличаться в зависимости от того, что вы пытаетесь сделать ... поэтому вы должны быть осторожны в этом отношении. Оформите инструмент под названием linqpad, вы можете попробовать в нем свой запрос и увидеть исполняемый SQL.

Кроме того, он запускается при выполнении итерации по коллекции или при вызове такого метода, как ToList ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...