User Tools

Site Tools


developer:linq

This is an old revision of the document!


LINQ-to-SQL и контенты QP7.Framework

Решаемые задачи

Работа с контентами упрощается за счет того, что:

  • Доступ к полям становится типизированным, с поддержкой IntelliSense.
  • LINQ-to-SQL предоставляет большое количество встроенных операций для работы с наборами данных. Единицами данных в этих наборах в нашем случае будут являться статьи.
  • Становится доступным поддержка декларативного связывания контентов с контролами (по DataSourceID) с помощью стандартного класса LinqDataSource.
  • Добавляется возможность редактирования статей с помощью LINQ-классов. Что вместе с предыдущим пунктом дает возможность использования, например, редактируемого Grid для контентов QP7.
  • Связанные таблицы становятся доступными как свойства (включая связи многие-ко-многим).

Предварительная настройка

  • В конфигурационный файл Backend нужно добавить параметр SqlMetalPath, определяющий путь к стандартной утилите генерации SQL-классов. Данная утилита устанавливатся вместе с Visual Studio 2008. Путь к ней может выглядеть так: C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe. Если на целевом компьютере не установлена Visual Studio, утилиту можно просто скачать.
  • Необходимо дать право доступа Modify пользователю NETWORK SERVICE на папку App_Code для возможности генерации файлов классов и папку App_Data для генерации промежуточных файлов отображений.
  • В процессе работы утилита SQLMetal может выдавать ошибки, которые можно посмотреть в файле sqlmetal.log в папке App_Data. Ошибки обычно связаны с конфликтами имен.
  • Если на сайте не использовался LINQ-to-SQL, то необходимо добавить в web.config ссылки на соответствующие сборки:
<system.web>
	<compilation>
		<assemblies>
...
			<add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
			<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
			<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
		</assemblies>
...
	</compilation>
</system.web>
...
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5" />
        <providerOption name="WarnAsError" value="false" />
      </compiler>
    </compilers>
  </system.codedom>

Настройка сборки контентов в классы LINQ-to-SQL

Сборка контентов QP7 в классы LINQ-to-SQL может осуществляться в двух режимах:

  1. С использованием БД. При этом будут использованы специальные настройки LINQ-to-SQL, которые задаются в свойствах контентов и полей.
  2. С использованием пользовательского файла отображения. При этом файл может быть как составлен разработчиком вручную, так и сгенерирован бэкендом по умолчанию.

Переключение режимов осуществляется опцией Использовать прямое отображение из базы данных (Use direct mapping from database) на уровне сайта. Cама сборка запускается кнопкой Собрать Контенты (Assemble Contents) на странице Контенты (Contents). При этом в папке App_Code происходит полная перегенерация всех LINQ-классов текущего сайта. Следует иметь в виду, что данный процесс с большой долей вероятности приведет к перегрузке домена приложения, поэтому его стоит с осторожностью применять на продукционных сайтах.

Настройка отображения с использованием БД

Настройки уровня сайта

  • Импортировать файл отображения в базу данных(Import mapping file to database) – позволяет импортировать существующий пользовательский файл отображения в базу данных для последующей настройки через бэкенд QP7 и генерации файла отображения в автоматическом режиме(опция Использовать прямое отображение из базы данных (Use direct mapping from database)). При успешном выполнении импорта опция Импортировать файл отображения в базу данных (Import mapping file to database) автоматически сбрасывается, а опция Использовать прямое отображение из базы данных (Use direct mapping from database) автоматически устанавливается.
  • Использовать прямое отображение из базы данных (Use direct mapping from database) – переключает режимы сборки LINQ-to-SQL классов между использованием файла отображения, созданного вручную и его автоматической генерацией на основе информации из БД. Все оставшиеся опции уровня сайта доступны только, когда данная опция включена.
  • Имя строки подключения (Connection string name) – Название строки соединения в секции connectionStrings файла web.config сайта. По умолчанию - qp_database.
  • Заменять URL (Replace URLs) – Включает замену плейсхолдеров <%=site_url%> и <%=upload_url%> для полей типа String, VisualEdit и Textbox. Замена работает в обе стороны, как при загрузке, так и при сохранении. Включение этой опции позволяет LINQ-классам поддерживать стандартное поведение Publishing Container'ов.
  • Использовать длинные URL (Use long URLs) – Модифицирует предыдущую опцию так, что замена будет проводиться на абсолютные URL, а не на относительные (по умолчанию). Аналогичная опция есть для Publishing Container'ов.
  • Пространство имен для генерируемых классов (Namespace for generated classes) – Пространство имен, в котором будут сгенерированы LINQ-классы. По умолчанию - пустое.
  • Имя контекстного класса (Context Class Name) – Имя контекстного класса. По умолчанию - QPDataContext.
  • Выполнять генерацию, независимую от БД (Proceed DB-independent generation) – Включение данной опции позволяет генерировать код, переносимый между различными БД. В этом случае сопоставление между сущностными классами и таблицами БД, осуществляется с помощью специального .map-файла, который также генерируется в этом режиме. Имя .map-файла совпадает с именем контекстного класса.
  • Генерировать только .map-файл (Generate only .map file) – Модификация предыдущей опции. Нужна в случае выполнения на данной БД переносимого кода, который был сгенерирован на другой БД. Таким образом, от данной БД требуется только сопоставление между сущностными классами и таблицами БД.

Особенности механизма генерации LINQ-классов

Статический DataContext

Доступен как LinqHelper.Context. Рекомендуется к использованию вместо создания каждый раз нового контекста через using (QPDataContext ctx = new QPDataContext()), кроме тех случав, когда необходимо работать с несколькими контекстами сразу.

Поддержка фильтрации M2M-полей на уровне SQL

Для этого генерируются отдельные узловые классы для каждой связи. На уровне БД эти классы отображаются на специальные представления (LINK_NNN), которые ссылаются на единую физическую таблицу ITEM_TO_ITEM. Все используемые узловые сущности генерируются автоматически, если же необходимо заменить их названия, это можно сделать в настройках поля Many-To-Many или через тег link файла отображения, задав в качестве идентификатора атрибут ID, и желаемые имена – в атрибутах mapped_name и mapped_plural_name.

При написании LINQ-запроса с фильтрацией по M2M-полю на уровне SQL алгоритм следующий:

  • начинаем с узловой сущности
  • фильтруем по одной связанной сущности
  • делаем проекцию по второй связанной сущности
IQueryable<Article> art = ctx.ArticlesCategories.Where(n => n.Category.Title == "main").Select(m => m.Article);

Поддержка механизмом отслеживания изменений полей M2M.

Для изменения полей M2M достаточно только вызывать методы Add и Remove соответствующей коллекции. Никакие другие поля для срабатывания механизма отслеживания изменений изменять не надо.

Автоматическая замена плейсхолдеров

Поддержка стандартного поведения Publishing Container (подробнее) Замена плейсхолдеров <%=site_url%> и <%=upload_url%> производится для полей типа String, VisualEdit и Textbox. Замена работает в обе стороны, как при загрузке, так и при сохранении. Для включения этого механизма необходимо у тега schema в файле отображения выставить атрибут replaceUrls=“true”. Кроме того установкой атрибута useLongUrls=“true” можно модифицировать поведение механизма, замены так, что плейсхолдеры будут заменяться на абсолютные URL, а не на относительные.

Фильтрация по умолчанию

Поддержка стандартного поведения Publishing Container. Необходимо для того, чтобы работало расписание публицкации, workflow, архив. В предыдущих версиях реализовалось через вызов метода расширения ForFrontEnd(). В текущей версии метод оставлен для обратной совместимости, но в случае включенной фильтрации по умолчанию никаких действий не выполняет. Опция Использовать фильтрацию по умолчанию (Use default filtration) настраивается на уровне контента. При включенной опции 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) при создании нового экземпляра класса и возможность их изменения.

Пример использования для добавления статьи

	NewsArticle art = new NewsArticle();
        art.Title = "some title";
	art.Text = "some text";
	LinqHelper.Context.NewsArticles.InsertOnSubmit(art);
	LinqHelper.Context.SubmitChanges();

LINQ-классы и кэширование

В quantumart.dll добавлен обобщенный (generic) метод кэширования GetCachedEntity:

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)

Основное назначение: кэширование произвольных пользовательских коллекций, в том числе полученных с помощью LINQ. Обычно это: Dictionary<K, V>, List<T>.

Пример использования:

DBConnector cnn = new DBConnector();
List<Banner> banners = cnn.CacheManager.GetCachedEntity<List<Banner>>(pageAddress, 10, GetPageBanners);

Где GetPageBanners – метод, возвращающий List<Banner>, который будет вызван только при заполнении кэша. Метод может быть определен как без параметров, так и с единственным строковым параметром. Во втором случае в метод будет передано значение ключа (параметр key).

Метод может использоваться для кэширования любых ссылочных типов. Для того, чтобы кэшировать значимый тип (value type), необоходимо выполнить принудительный boxing (число можно для этого, например, преобразовать в строку). Данный метод также позволяет кэшировать null-значения, используя для них специальную обертку.

Основные ошибки использования LINQ-классов

  • Многократное выполнение одних и тех же запросов без необходимости.
  • Отсутствие понимания, что выполняется на веб-сервере, а что – на сервере баз данных
  • Получение от SQL-сервера лишней информации (аналог в SQL – select *), когда можно обойтись ограниченным набором полей с помощью select new.
  • В конце цепочки операций LINQ в большинстве случаев желательно явно овеществлять результат (например, с помощью ToList()). Результат должен быть не IQueryable<T>, а IEnumerable<T> или T, иначе последующий foreach может привести к новому SQL-запросу на каждой итерации.

Discussion

Enter your comment
 
developer/linq.1304581989.txt.gz · Last modified: 2011/05/05 10:53 by celutp