Исходя из параметров запроса, загрузить данные из источника — рутина, с которой сталкивается разработчик веб-страниц. В статье рассмотрен подход, позволяющий сократить время необходимое для связывания параметров страницы с источником данных. Описана реализация этого подхода для платформы .NET.
Рассмотрим пример:
Интернет магазин:
В качестве параметра для страниц передается уникальный идентификатор товара или поставщика соответственно. Реализован следующий функционал:
Похожую функциональность часто приходиться реализовывать при разработке страниц сайта. Хотелось бы выделить ее в отдельный компонент, который мог бы работать с различными типами сущностей(товар, поставщик). Он должен быть простым в использовании и не значительно влиять на производительность.
Критичные свойства компонента, определяющие его использование:
Какие данные необходимы компоненту для выполнения нужных действий? Всего лишь набор правил: имя параметра — тип сущности! Действительно, зная имя параметра, можно получить идентификатор сущности, зная тип сущности и идентификатор сущности можно извлечь сущность из источника данных. Для приведенного выше примера может быть так:
запрос: <страница>?poductId=<идентификатор продукта>
правило: productId — Product
по параметру «productId» предается идентификатор сущности типа «Product»
запрос: <страница>?supplierId=<идентификатор поставщика>
правило: supplierId — Supplier
по парметру «supplierId» предается идентификатор сущности типа «Suppler»
Связывание может быть устроено по-разному и хотелось, чтобы компонент мог использовать различные механизмы. Выделим в компоненте ту часть, которая обеспечивает взаимодействие с механизмом связывания, и будем менять ее в зависимости от механизма. Соответственно все такие части соответствуют единой абстракции (интерфейсу), обладая следующим функционалом:
Такой подход позволит упростить добавление новых механизмов связывания и их замену
Сами источники могут быть разными, и хотелось бы получить гибкий механизм доступа к ним. Можно выделить в компоненте часть, которая обеспечивает взаимодействие с источником данных, и менять ее в зависимости от источника. Соответственно все такие части соответствуют единой абстракции (интерфейсу), то есть обладают следующим функционалом:
Такой подход позволит упростить добавление новых источников и их замену
Эти же свойства предоставляют доступ разработчику к загруженным сущностям
Пример связки LinqToSqlClasses & WebPagе (с картинками:-)
Рассмотрим пример:
Интернет магазин:
- страница, на которой более детально можно посмотреть характеристики товар
- страница, на которой более детально можно посмотреть информации о поставщиках
В качестве параметра для страниц передается уникальный идентификатор товара или поставщика соответственно. Реализован следующий функционал:
- извлечение уникального идентификатора из строки запроса
- получение по идентификатору информацию по товару или поставщику соответственно
Похожую функциональность часто приходиться реализовывать при разработке страниц сайта. Хотелось бы выделить ее в отдельный компонент, который мог бы работать с различными типами сущностей(товар, поставщик). Он должен быть простым в использовании и не значительно влиять на производительность.
Критичные свойства компонента, определяющие его использование:
- выигрыш во времени — время, которое уходит на разработку страницы, с использованием компонента должно уменьшиться
- производительность — использование компонента не должно сильно уменьшить время обработки запроса к странице
Какие данные необходимы компоненту для выполнения нужных действий? Всего лишь набор правил: имя параметра — тип сущности! Действительно, зная имя параметра, можно получить идентификатор сущности, зная тип сущности и идентификатор сущности можно извлечь сущность из источника данных. Для приведенного выше примера может быть так:
запрос: <страница>?poductId=<идентификатор продукта>
правило: productId — Product
по параметру «productId» предается идентификатор сущности типа «Product»
запрос: <страница>?supplierId=<идентификатор поставщика>
правило: supplierId — Supplier
по парметру «supplierId» предается идентификатор сущности типа «Suppler»
Связывание со страницей
Разработчику нужен механизм, позволяющий связать страницу и компонент, то есть следующие:- задать набор правил (имя параметра — тип содержимого)
- получить сущности загруженные компонентом
Связывание может быть устроено по-разному и хотелось, чтобы компонент мог использовать различные механизмы. Выделим в компоненте ту часть, которая обеспечивает взаимодействие с механизмом связывания, и будем менять ее в зависимости от механизма. Соответственно все такие части соответствуют единой абстракции (интерфейсу), обладая следующим функционалом:
- получить имена параметров для заданной страницы
- получить тип параметра по имени параметра для заданной страницы
- получить сущность по имени параметра для заданной страницы
- передать заданной страницы сущность по имени параметра
Такой подход позволит упростить добавление новых механизмов связывания и их замену
Работа с коллекциями
Часто приходиться иметь дело не с отдельными сущностями, а с коллекциями сущностей, когда по параметру передается набор идентификаторов. Соответственно по набору идентификаторов нужно загружать набор сущностей. Поддержка такой функциональности со стороны компонента ускорит процесс разработки.Работа с источниками данных
Идентификатор сущности строиться на основании источника данных и может иметь сложную структуру. Если использовать в качестве источника реляционную базу данных, то идентификатором может быть основной ключ таблицы, в которой хранится сущность. Основной ключ в свою очередь может быть построен по нескольким полям таблицы. Чтобы компонент мог работать поверх любой структуры источника надо предоставить возможность работы со сложными идентификаторами.Сами источники могут быть разными, и хотелось бы получить гибкий механизм доступа к ним. Можно выделить в компоненте часть, которая обеспечивает взаимодействие с источником данных, и менять ее в зависимости от источника. Соответственно все такие части соответствуют единой абстракции (интерфейсу), то есть обладают следующим функционалом:
- получение сущности по идентификатору (сущностей по идентификаторам)
- получение идентификатора по сущности (идентификаторов по сущностям)
Такой подход позволит упростить добавление новых источников и их замену
Не только страницы
Страница является хорошим примером использования компонента. Она одновременно является источником параметров (имя параметра — идентификатор) и также целевым объектом, которому нужно передать сущности из источника данных. Если считать, что параметры задаются каким-то другим способом, то данный компонент можно применить для произвольного объекта, которому нужно передать сущности из базы данных. Например, можно хранить конфигурацию в виде: имя параметра — идентификатор, а потом с помощью компонента передать нужные сущности целевому объекту.Реализация для .NET — Binding Framework
Binding Framework — библиотека (.dll). В ней есть:- основное
- интерфейс позволяющий абстрагироваться от механизма связывания
- интерфейс позволяющий абстрагироваться от источника данных
- обработчик параметров, опирающийся на интерфейс механизма связывания и интерфейс источника данных
- структура данных для параметров (имя параметра — идентификатор)
- структура данных позволяющая работать единообразно и с отдельными сущностями и с коллекциями
- реализации
- связывание со страницей через свойства + атрибуты
- работа с источником данных: LinqToSqlClasses
- получение параметров из NameValueCollection (QueryString)
- готовая связка LinqToSqlClasses & WebPage (System.Data.Linq.DataContext & System.Web.UI.Page)
Свойства + атрибуты
В зависимости от сущностей, которые хотим загружать через компонент, определяем свойства страницы. Тип свойства может быть следующий:- тип сущности
- типизированная коллекция (IEnumerable<T>, T — тип сущности). Эти свойства также помечаются атрибутом, в котором указано имя параметра
Эти же свойства предоставляют доступ разработчику к загруженным сущностям
Связка LinqToSqlClasses & WebPagе
При работе с коллекциями данная связка передает свойству страницы не готовый набор сущностей, а коллекцию IQuerable<T>, T-тип сущности, что позволяет отложить сам запрос до момента использования, применить дополнительные критерии отбора.Ссылки
Binding FrameworkПример связки LinqToSqlClasses & WebPagе (с картинками:-)