2010-03-23 2 views
1

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

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

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

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

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

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. Мы должны создать простые вопросы, верно?

+0

Для получения максимальной скорости я настоятельно рекомендую LINQPad. Трудно описать, но в основном это запросы LINQ, и вы можете легко увидеть, что происходит в фоновом режиме. Отлично подходит для тестирования новых запросов. http://www.linqpad.net/ – Steve

ответ

3

Вы верны. 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

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

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

+0

Так что невозможно использовать такие ярлыки, верно? Интересно, где я могу найти некоторые ресурсы, чтобы прочитать об этом. К сожалению, книги не объясняют эти понятия. – Alex

+0

Приношу свои извинения, я пропустил последнюю часть. Я получаю команды для работы в SQL-запросах ... как насчет этого не работает, так как вы получаете сообщение об ошибке или результаты не возвращаются? Если возникает ошибка, в первом запросе может возникнуть ошибка. В противном случае, если результаты не вернутся, трудно сказать, не глядя на запрос БД; LinqPad может помочь в этом. Содержит один из немногих поддерживаемых массивом методов, поэтому я не думаю, что это с этим, если оба объекта одного типа (оба имеют значения ID). –

1

Entity Framework или LINQ запросы могут быть сложны иногда. Иногда вы удивляетесь эффективности генерируемого запроса sql, и иногда запрос настолько сложный и неэффективный, что вы будете ударять по лбу.

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

1

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

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

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

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

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

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