|
|
От: |
VladD2
|
www.nemerle.org |
| Дата: | 29.12.07 13:01 | ||
| Оценка: | 42 (11) | ||
Многие воспринимают LINQ to SQL как очередной O/R mapper, но реализованный Microsoft. Учитывая, что от Microsoft всегда ожидают намного большего, чем от более бедных компаний, и тем более от Open Source-разработчиков, у многих при первом знакомстве с LINQ to SQL наступает серьезное разочарование. Однако это разочарование вызвано неправильным пониманием сути используемого в LINQ to SQL подхода. Дело в том, что LINQ to SQL не является O/R mapper-ом. На самом деле LINQ – это абстрактное средство обработки списков, а отдельные разновидности LINQ, такие как LINQ to SQL или LINQ to XML, просто рассматривают некий источник данных как набор списков. Задача средств отображения, присутствующих, например, в LINQ to SQL, не в том, чтобы создать объектную модель, позволяющую скрыть детали БД и обеспечить эффективную обработку данных императивными средствами (в основном фильтрацию списков в циклах), а в том, чтобы ввести в программу некий набор классов, предназначенных для считывания в них данных из таблиц СУБД. При этом LINQ to SQL хотя и позволяет работать с такими классами императивными средствами, но заранее предупреждает, что это будет неэффективно и неудобно. Вместо этого LINQ to SQL предлагает использовать статически типизируемые, проверяемые во время компиляции, SQL-подобные запросы. Эти запросы транслируется в эффективный SQL, который выполняется СУБД. Результаты выполнения этих запросов преобразуются в списки типизированных объектов, которые удобно обрабатывать в таких объектно-ориентированных языках программирования, как VB и C#. Простой пример: предположим, у нас таблица покупателей (Customer), ссылающаяся на список заказов (у каждого покупателя может быть 0 или более заказов, Order), при этом в каждом заказе может быть 0 или более позиций (OrderDetail), и в наши задачи входит посчитать, сколько конкретному покупателю было продано единиц некоторого товара. Предположим, что идентификатор покупателя – ТКС, а идентификатор товара – БумагаА4. И классический O/R mapper, и LINQ to SQL при создании объектной модели для связи между таблицами генерируют соответствующие коллекции. Для нашего примера в классе Customer будет создана коллекция Orders, содержащая список объектов типа Order, а Order будет содержать коллекцию типа OrderDetails, содержащую, соответственно, список позиций заказов (объектов OrderDetail). При использовании традиционного O/R mapper-а было бы совершенно нормально написать код, который получает (с помощью некоторой хитрой функции Lookup) объект по его идентификатору, а дальше, с помощью двух вложенных циклов, пробегает по его коллекции, отбирая нужные элементы. Казалось бы, объем данных невелик (сколько может быть заказов у одного покупателя?), и перебор должен произойти практически мгновенно. Нужную позицию можно отфильтровать с помощью if. Однако ни O/R mapper, ни, тем более, СУБД не знают о наших замечательных намерениях и, если они не используют специальных техник, это приведет к тому, что для выборки каждого объекта будет выполнено отдельное обращение к БД. Конечно, хороший O/R mapper буквально напичкан специальными техниками, сглаживающими подобные неприятности (в частности, они могут выполнять опережающее чтение). Однако без тотального кэширования данных движком O/R mapper и, фактически, дублирования функций СУБД высокой производительности добиться не удастся. Поскольку серьезные БД в память априори не помещаются (тем более в объектном представлении), производительность всех без исключения O/R mapper-ов оставляет желать лучшего. Обратите внимание – это проблема системного характера, и решить ее принципиально, используя данный подход, невозможно. Как же быть? Более 20 лет назад производители СУБД (а именно IBM) решили эту проблему для своих продуктов. Решением был переход от навигационной системы к запросной с использованием языка запросов SQL. SQL в декларативной манере говорит СУБД, какие данные нужны клиенту, что потенциально позволяет СУБД построить эффективный план запроса и возвратить клиенту только требуемые данные. При этом экономятся как ресурсы сервера, так и трафик. Так вот, хотя LINQ to SQL и содержит набор возможностей, похожих на предоставляемые O/R mapper-ами вроде Hybernate, основным средством доступа к данным в нем является SQL-подобный язык запросов. LINQ же обеспечивает его безопасность, проверку ошибок на стадии компиляции, а поддержка Intellisense для запросов, встроенных в язык, появившаяся в VS 2008, существенно повышает производительность программирования. Именно так и нужно смотреть на LINQ, а что касается O/R mapper-а от Microsoft, он, по всей видимости, вскоре появится под названием LINQ to Entity, но, скорее всего, и эта реализация будет склонять программиста к использованию интегрированного языка запросов, а не императивного доступа к данным.