Зачем писать собственный поставщик LINQ? - PullRequest
7 голосов
/ 10 декабря 2010

В чем преимущество написания собственного поставщика LINQ по сравнению с написанием простого класса, который реализует IEnumerable?

Например, этот Quesiton показывает Linq2Excel:

var book = new ExcelQueryFactory(@"C:\Users.xls");
var administrators = from x in book.Worksheet<User>()
                     where x.Role == "Administrator"
                     select x;

Но в чем преимущество над «наивной» реализацией, как IEnumerable?

Ответы [ 4 ]

13 голосов
/ 10 декабря 2010

Цель провайдера Linq состоит в том, чтобы в основном «перевести» деревья выражений Linq (которые создаются за кулисами запроса) на родной язык запросов источника данных. В тех случаях, когда данные уже находятся в памяти, вам не нужен поставщик Linq; Linq 2 Объекты в порядке. Однако, если вы используете Linq для связи с внешним хранилищем данных, таким как СУБД или облако, это абсолютно необходимо.

Основная предпосылка любой структуры запросов состоит в том, что механизм источника данных должен выполнять как можно большую часть работы и возвращать только те данные, которые необходимы клиенту. Это связано с тем, что источник данных, как предполагается, лучше знает, как управлять хранящимися в нем данными, а также потому, что передача данных по сети является относительно дорогостоящей во времени и поэтому должна быть минимизирована. Теперь, на самом деле, эта вторая часть «возвращает только те данные, которые запрашивает клиент»; сервер не может читать мысли вашей программы и знать, что ей действительно нужно; он может дать только то, что просил. Вот где интеллектуальный провайдер Linq просто поражает «наивной» реализацией. Используя IQueryable сторону Linq, которая генерирует деревья выражений, поставщик Linq может преобразовать дерево выражений, скажем, в оператор SQL, который СУБД будет использовать для возврата записей, которые клиент запрашивает в операторе Linq. Наивная реализация потребовала бы извлечения ВСЕХ записей с использованием некоторого широкого оператора SQL, чтобы предоставить клиенту список объектов в памяти, а затем вся работа по фильтрации, группировке, сортировке и т. Д. Выполняется клиентом.

Например, предположим, что вы использовали Linq для получения записи из таблицы в БД по ее первичному ключу. Поставщик Linq может перевести dataSource.Query<MyObject>().Where(x=>x.Id == 1234).FirstOrDefault() в «SELECT TOP 1 * из MyObjectTable WHERE Id = 1234». Это возвращает ноль или одну запись. «Наивная» реализация, вероятно, будет отправлять серверу запрос «SELECT * FROM MyObjectTable», а затем использовать сторону IEnumerable Linq (которая работает с классами в памяти) для выполнения фильтрации. В утверждении, которое вы ожидаете получить 0-1 из таблицы с 10 миллионами записей, какие из них, по вашему мнению, будут выполнять работу быстрее (или даже работать вообще, без нехватки памяти)?

7 голосов
/ 10 декабря 2010

Вам не нужно писать провайдера LINQ, если вы хотите использовать для своих целей только функцию LINQ-to-Objects (то есть foreach), которая в основном работает со списками в памяти.

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

3 голосов
/ 10 декабря 2010

В целом производительность. Если у вас есть какой-то индекс, вы можете сделать запрос намного быстрее, чем это возможно для простого IEnumerable<T>.

Хороший пример - Linq-To-Sql. Здесь вы преобразуете оператор linq в другой, понятный SQL-серверу. Таким образом, сервер будет выполнять фильтрацию, упорядочение, ... используя индексы, и ему не нужно отправлять всю таблицу клиенту, который затем делает это с linq-to-objects.

Но есть и более простые случаи, когда это может быть полезно:

Если у вас есть индекс дерева над свойством Time, то запрос диапазона, такой как .Where(x=>(x.Time>=now)&&(x.Time<=tomorrow)), можно оптимизировать много, и не нужно перебирать каждый элемент в перечисляемом.

1 голос
/ 10 декабря 2010

LINQ обеспечит максимально возможное отложенное выполнение для повышения производительности.

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

http://msdn.microsoft.com/en-us/vcsharp/ff963710.aspx

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

...