This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
developer:linq [2011/05/05 11:54] celutp |
developer:linq [2011/09/14 12:17] (current) celutp |
||
---|---|---|---|
Line 11: | Line 11: | ||
===== Предварительная настройка ===== | ===== Предварительная настройка ===== | ||
* В [[admin:config|конфигурационный файл Backend]] нужно добавить параметр **SqlMetalPath**, определяющий путь к стандартной утилите генерации SQL-классов. Данная утилита устанавливатся вместе с Visual Studio 2008. Путь к ней может выглядеть так: ''C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe''. Если на целевом компьютере не установлена Visual Studio, утилиту можно просто [[http://downloads.quantumart.ru/sqlmetal.zip|скачать]]. | * В [[admin:config|конфигурационный файл Backend]] нужно добавить параметр **SqlMetalPath**, определяющий путь к стандартной утилите генерации SQL-классов. Данная утилита устанавливатся вместе с Visual Studio 2008. Путь к ней может выглядеть так: ''C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe''. Если на целевом компьютере не установлена Visual Studio, утилиту можно просто [[http://downloads.quantumart.ru/sqlmetal.zip|скачать]]. | ||
- | * Необходимо дать право доступа //Modify// пользователю NETWORK SERVICE на папку //App_Code// для возможности генерации файлов классов и папку //App_Data// для генерации промежуточных файлов отображений. | + | * Необходимо дать право доступа //Modify// пользователю, под которым запущен Application Pool (обычно это NETWORK SERVICE), на папку //App_Code// для возможности генерации файлов классов и папку //App_Data// для генерации промежуточных файлов отображений. |
* В процессе работы утилита **SQLMetal** может выдавать ошибки, которые можно посмотреть в файле //sqlmetal.log// в папке //App_Data//. Ошибки обычно связаны с конфликтами имен. | * В процессе работы утилита **SQLMetal** может выдавать ошибки, которые можно посмотреть в файле //sqlmetal.log// в папке //App_Data//. Ошибки обычно связаны с конфликтами имен. | ||
* Если на сайте не использовался LINQ-to-SQL, то необходимо добавить в //web.config// ссылки на соответствующие сборки: | * Если на сайте не использовался LINQ-to-SQL, то необходимо добавить в //web.config// ссылки на соответствующие сборки: | ||
Line 41: | Line 41: | ||
Сборка контентов QP7 в классы //LINQ-to-SQL// может осуществляться в двух режимах: | Сборка контентов QP7 в классы //LINQ-to-SQL// может осуществляться в двух режимах: | ||
- | - С использованием БД. При этом будут использованы специальные настройки LINQ-to-SQL, которые задаются в свойствах контентов и полей. | + | - [[developer:linq:db_mapping|С использованием БД]]. При этом будут использованы специальные настройки LINQ-to-SQL, которые задаются в свойствах сайта, контентов и полей. |
- | - С использованием [[developer:linq:mapping| пользовательского файла отображения]]. При этом файл может быть как составлен разработчиком вручную, так и сгенерирован бэкендом по умолчанию. | + | - [[developer:linq:mapping|С использованием пользовательского файла отображения]]. При этом файл может быть как составлен разработчиком вручную, так и сгенерирован бэкендом по умолчанию. |
Переключение режимов осуществляется опцией **Использовать прямое отображение из базы данных** (**Use direct mapping from database**) на [[:site_configuration#Настройки_сборки_в_LINQ|уровне сайта]]. Cама сборка запускается кнопкой **Собрать Контенты** (**Assemble Contents**) на странице **Контенты** (**Contents**). При этом в папке //App_Code// происходит полная перегенерация всех LINQ-классов текущего сайта. Следует иметь в виду, что данный процесс с большой долей вероятности приведет к перегрузке домена приложения, поэтому его стоит с осторожностью применять на продукционных сайтах. | Переключение режимов осуществляется опцией **Использовать прямое отображение из базы данных** (**Use direct mapping from database**) на [[:site_configuration#Настройки_сборки_в_LINQ|уровне сайта]]. Cама сборка запускается кнопкой **Собрать Контенты** (**Assemble Contents**) на странице **Контенты** (**Contents**). При этом в папке //App_Code// происходит полная перегенерация всех LINQ-классов текущего сайта. Следует иметь в виду, что данный процесс с большой долей вероятности приведет к перегрузке домена приложения, поэтому его стоит с осторожностью применять на продукционных сайтах. | ||
Line 48: | Line 48: | ||
Кроме этого, на [[:site_configuration#Настройки_сборки_в_LINQ|уровне сайта]] существует опция **Импортировать файл отображения в базу данных**(**Import mapping file to database**), которая позволяет импортировать существующий [[developer:linq:mapping|пользовательский файл отображения]] в базу данных для последующей настройки через бэкенд QP7 и генерации файла отображения в автоматическом режиме. При успешном выполнении импорта данная опция автоматически сбрасывается, а опция **Использовать прямое отображение из базы данных** (**Use direct mapping from database**) автоматически устанавливается. | Кроме этого, на [[:site_configuration#Настройки_сборки_в_LINQ|уровне сайта]] существует опция **Импортировать файл отображения в базу данных**(**Import mapping file to database**), которая позволяет импортировать существующий [[developer:linq:mapping|пользовательский файл отображения]] в базу данных для последующей настройки через бэкенд QP7 и генерации файла отображения в автоматическом режиме. При успешном выполнении импорта данная опция автоматически сбрасывается, а опция **Использовать прямое отображение из базы данных** (**Use direct mapping from database**) автоматически устанавливается. | ||
- | Опция **Импортировать файл отображения в базу данных**(**Import mapping file to database**) также может быть полезна для первичного заполнения настроек LINQ-to-SQL для существующего сайта с большим количеством контентов. Для этого сначала генерируется [[developer:linq:mapping| пользовательский файл отображения]] по умолчанию (при отключенной опции **Использовать прямое отображение из базы данных** (**Use direct mapping from database**), а затем проводится его импорт. | + | Опция **Импортировать файл отображения в базу данных**(**Import mapping file to database**) также может быть полезна для первичного заполнения настроек LINQ-to-SQL для существующего сайта с большим количеством контентов. Для этого сначала генерируется пользовательский файл отображения по умолчанию (при отключенной опции **Использовать прямое отображение из базы данных** (**Use direct mapping from database**), а затем проводится его импорт. |
+ | Генерация LINQ-to-SQL классов и вспомогательных файлов осуществляется в папки //App_Data// и //App_Code// сайта. Расположение этих папок вычисляется из расположения папки //bin//, которая настраивается в [[:site_configuration#папка_для_net-сборок|свойствах сайта]]. При этом предполагается, что папки //App_Data// и //App_Code// находятся на том же уровне в дереве папок, что и //bin//. | ||
+ | ===== Использование сгенерированных LINQ-to-SQL классов ===== | ||
- | ===== Особенности механизма генерации LINQ-классов ===== | + | - [[developer:linq:context|Использование контекстного класса]] |
+ | - [[developer:linq:M2M|Работа с M2M-полями]] | ||
+ | - [[developer:linq:container|Поддержка поведения Publishing Container]] | ||
+ | - [[developer:linq:service_field|Поддержка служебных полей контента]] | ||
+ | - [[developer:linq:image|Дополнительные свойства для полей-изображений]] | ||
+ | - [[developer:linq:caching|Кэширование]] | ||
+ | - [[developer:linq:components|Создание компонентов]] | ||
+ | - [[developer:linq:errors|Основные ошибки использования LINQ-to-SQL классов]] | ||
- | ==== Статический DataContext ==== | + | ===== Пример добавления статьи ===== |
- | Доступен как **LinqHelper.Context**. Рекомендуется к использованию вместо создания каждый раз нового контекста через ''using (QPDataContext ctx = new QPDataContext())'', кроме тех случав, когда необходимо работать с несколькими контекстами сразу. | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Поддержка фильтрации M2M-полей на уровне SQL ==== | + | |
- | + | ||
- | Для этого генерируются отдельные узловые классы для каждой связи. На уровне БД эти классы отображаются на специальные представления (//LINK_NNN//), которые ссылаются на единую физическую таблицу //ITEM_TO_ITEM//. Все используемые узловые сущности генерируются автоматически, если же необходимо заменить их названия, это можно сделать в настройках поля Many-To-Many или через тег ''link'' [[developer:linq:mapping|файла отображения]], задав в качестве идентификатора атрибут ID, и желаемые имена – в атрибутах //mapped_name// и //mapped_plural_name//. | + | |
- | + | ||
- | При написании LINQ-запроса с фильтрацией по M2M-полю на уровне SQL алгоритм следующий: | + | |
- | * начинаем с узловой сущности | + | |
- | * фильтруем по одной связанной сущности | + | |
- | * делаем проекцию по второй связанной сущности | + | |
- | <code c#>IQueryable<Article> art = ctx.ArticlesCategories.Where(n => n.Category.Title == "main").Select(m => m.Article);</code> | + | |
- | + | ||
- | ==== Поддержка механизмом отслеживания изменений полей M2M. ==== | + | |
- | Для изменения полей M2M достаточно только вызывать методы //Add// и //Remove// соответствующей коллекции. Никакие другие поля для срабатывания механизма отслеживания изменений изменять не надо. | + | |
- | + | ||
- | ==== Автоматическая замена плейсхолдеров ==== | + | |
- | Поддержка стандартного поведения Publishing Container ([[edit:url_auto_replace|подробнее]]) Замена плейсхолдеров ''<%=site_url%>'' и ''<%=upload_url%>'' производится для полей типа //String//, //VisualEdit// и //Textbox//. Замена работает в обе стороны, как при загрузке, так и при сохранении. Для включения этого механизма необходимо у тега ''schema'' в [[developer:linq:mapping|файле отображения]] выставить атрибут ''replaceUrls="true"''. Кроме того установкой атрибута ''useLongUrls="true"'' можно модифицировать поведение механизма, замены так, что плейсхолдеры будут заменяться на абсолютные URL, а не на относительные. | + | |
- | + | ||
- | ==== Фильтрация по умолчанию ==== | + | |
- | Поддержка стандартного поведения Publishing Container. Необходимо для того, чтобы работало расписание публицкации, workflow, архив. В предыдущих версиях реализовалось через вызов метода расширения **ForFrontEnd()**. В текущей версии метод оставлен для обратной совместимости, но в случае включенной фильтрации по умолчанию никаких действий не выполняет. Опция **Использовать фильтрацию по умолчанию** (**Use default filtration**) настраивается [[:content|на уровне контента]]. При включенной опции LINQ-класс отображается не на таблицу CONTENT_NNN, а на представление CONTENT_NNN_LIVE (для stage-режима используется аналогичное представление CONTENT_NNN_STAGE вместо CONTENT_NNN_UNITED) | + | |
- | + | ||
- | + | ||
- | ==== Улучшенная логика служебных полей ==== | + | |
- | * Альтернативные свойства для служебных полей в соответствии с Pascal-нотацией: //Created//, //Modified//, //LastModifiedBy//, //Visible// (bool), //Archive// (bool), //StatusType// (ссылка на соответствующий тип). Старые названия поддерживаются для обратной совместимости. | + | |
- | * Автообновление полей //Created// и //Modified// при соответствующих событиях (//SubmitChanges//) | + | |
- | * Автосоздание служебных полей (//Visible//, //Archive//, //StatusType//) при создании нового экземпляра класса и возможность их изменения. | + | |
- | + | ||
- | ===== Пример использования для добавления статьи ===== | + | |
<code c#> | <code c#> | ||
NewsArticle art = new NewsArticle(); | NewsArticle art = new NewsArticle(); | ||
Line 93: | Line 72: | ||
LinqHelper.Context.SubmitChanges(); | LinqHelper.Context.SubmitChanges(); | ||
</code> | </code> | ||
- | |||
- | ===== LINQ-классы и кэширование ===== | ||
- | |||
- | В //quantumart.dll// добавлен обобщенный (generic) метод кэширования //GetCachedEntity//: | ||
- | |||
- | <code c#> | ||
- | public T GetCachedEntity<T>(string key, Func<T> fillAction) | ||
- | public T GetCachedEntity<T>(string key, Func<string, T> fillAction) | ||
- | public T GetCachedEntity<T>(string key, double cacheInterval, Func<T> fillAction) | ||
- | public T GetCachedEntity<T>(string key, double cacheInterval, Func<string, T> fillAction) | ||
- | </code> | ||
- | Основное назначение: кэширование произвольных пользовательских коллекций, в том числе полученных с помощью LINQ. Обычно это: //Dictionary<K, V>//, //List<T>//. | ||
- | |||
- | Пример использования: | ||
- | |||
- | <code c#> | ||
- | DBConnector cnn = new DBConnector(); | ||
- | List<Banner> banners = cnn.CacheManager.GetCachedEntity<List<Banner>>(pageAddress, 10, GetPageBanners); | ||
- | </code> | ||
- | |||
- | Где //GetPageBanners// – метод, возвращающий //List<Banner>//, который будет вызван только при заполнении кэша. Метод может быть определен как без параметров, так и с единственным строковым параметром. Во втором случае в метод будет передано значение ключа (параметр //key//). | ||
- | |||
- | Метод может использоваться для кэширования любых ссылочных типов. Для того, чтобы кэшировать значимый тип (value type), необоходимо выполнить принудительный //boxing// (число можно для этого, например, преобразовать в строку). Данный метод также позволяет кэшировать //null//-значения, используя для них специальную обертку. | ||
- | |||
- | ===== Основные ошибки использования LINQ-классов ===== | ||
- | |||
- | * Многократное выполнение одних и тех же запросов без необходимости. | ||
- | * Отсутствие понимания, что выполняется на веб-сервере, а что -- на сервере баз данных | ||
- | * Получение от SQL-сервера лишней информации (аналог в SQL -- //select *//), когда можно обойтись ограниченным набором полей с помощью //select new//. | ||
- | * В конце цепочки операций LINQ в большинстве случаев желательно явно овеществлять результат (например, с помощью //ToList()//). Результат должен быть не //IQueryable<T>//, а //IEnumerable<T>// или T, иначе последующий //foreach// может привести к новому SQL-запросу на каждой итерации. | ||