Перечисления. Сторона СУБД и прямые SQL-запросы

22 февраля 2013

Предисловие

Перечисление

Платформа 1С:Предприятие 8.x в составе доступных метаданных конфигурации имеет такой объект как "Перечисление". Перечисления используются для создания списков значений в прикладном решении, которые не изменяются в процессе работы. 

Например, практически во всех типовых конфигурациях есть перечисление "ПолФизическихЛиц" (или подобное), содержащее два значения: "Мужской" и "Женский". В принципе другого и быть не может =).

Сегодня в статье мы рассмотрим как перечисления хранятся в таблицах базы данных на стороне СУБД, и как можно получить значения перечисления прямым запросом к SQL-таблице. В качестве СУБД в примерах будет использоваться MS SQL 2008.

Хранение в базе данных

В тестовой конфигурации создадим перечисление "Важность" и заполним ее соответствующими значениями (см. следующий скриншот).

Перечисление "Важность" в тестовой конфигурации

В программе "SQL Server Managment Studio" откроем связанную с тестовой информационной базой SQL-базу и рассмотрим структуру SQL-таблицы созданного перечисления.

SQL-таблица перечисления

Как мы видим, таблица для перечисления носит название "Enum8". При добавлении в конфигурацию перечислений, платформа создает для каждого их них соответствующую SQL-таблицу с именем:

"Enum<ИдентификаторТаблицы>", где

"ИдентификаторТаблицы" - некоторое значение, которое 1С:Предприятие добавляет для однозначной идентификации таблицы.

Таблица имеет два столбца: 

  1. "_IDRRef" - ссылка на значение перечисления с типом binary(16).
  2. "_EnumOrder" - число (numeric(10,0)) для сортировки значений перечисления.

Оба столбца хранят значения стандартных реквизитов для значений перечисления. На следующем скриншоте представлены стандартные реквизиты любого перечисления.

Стандартные реквизиты  перечисленияСтоит отметить, что добавлять собственные реквизиты к перечислению платформа не позволяет, следовательно состав столбцов SQL-таблицы всегда представлен стандартными реквизитами и не изменяется.

Рассмотрим содержимое таблицы "Enum8" для созданного ранее перечисления "Важность" (см. скриншот ниже).

Содержимое SQL-таблицы перечисления "Важность"Самое интересное в данном случае - это отсутствие имен перечислений в таблице.

Может возникнуть логичный вопрос: "Как система получает наименования перечислений при обращении к ним?".

На самом деле все просто - платформа хранит соответствие наименования в структуре метаданных к конкретному значению перечисления. При получении значения перечисления 1С:Предприятие получает  его представление для удобной работы пользователя (представьте что было бы, если вместо значения перечисления "Мужской" пользователь увидит GUID(!)).

Таким образом, платформа хранит значения перечислений в таблицах с имением типа "Enum&lt;ИдентификаторТаблицы&gt;", при этом в таблицу записываются только ссылка на значение перечисления и порядковое число, по которому происходит сортировка.

Прямой запрос

Выше было сказано, что в SQL-таблице для перечислений не хранятся наименования для значений. Поэтому стал интересен вопрос: "Можно ли напрямую SQL-запросом получить перечисления с наименованием?".

Есть два варианта: 

  1. Получить содержимое SQL-таблицы перечисления, а затем по полю "Порядок" ("_EnumOrder" в SQL-таблице) получить соответствующее значение перечисления из метаданных конфигурации, где будет доступны свойства "Наименование", "Синоним" и другие.
  2. Получить наименования значений перечисления непосредственно в SQL-запросе.

Выберем наиболее интересный с точки зрения реализации второй вариант и напишем SQL-запрос для получения значений перечисления "Важность".

Для создания запроса будем использовать "SQL Server Managtment Studio". Для начала напишем запрос для получения всех записей из таблицы "Enum8". Он выглядит следующим образом:

Текст запроса на выборку всех записей из SQL-таблицы перечисления "Важность"

В запросе мы выбираем все доступные поля. При указании источника, в начале указываем имя базы данных (в текущем примере база называется "127.0.0.1", не перепутайте с адресом SQL-сервера). В конце указываем название таблицы, к которой делаем запрос.

Результат выполнения запроса Вы могли видеть на скриншоте выше. Поскольку перечисления предполагают относительно постоянный состав, в запросе мы будем определять наименования значений с помощью выражения"CASE". Мы будем сравнивать ссылки с заранее известными значениями и в соответствии с условием будет получать необходимое строковое представление. Поскольку ссылка имеет тип "binary(16)", просто сравнить значения со строкой не получится. Нужно будет конвертировать ссылку в строку и сравнивать со строковым значением.

Получаем  имя значения перечисления

Строковые значения для каждой из ссылки на значение перечисления мы можем получить заранее с помощью следующего запроса:

Получение значения ссылка в виде строки

По скриншоту выше стоит заметить следующее:

 
  1. Преобразование ссылки к строке производится с помощью системной функции "fn_varbintohexstr".
  2. В нашем примере значение поля "Link" и "LinkToString" на первый взгляд одинаковые. На самом же деле их типы различны ("binary(16)" у поля "Link" и "Hexdecimal string" у поля "LinkAsString").

В итоге мы можем написать SQL-запрос для получения значений перечисления "Важность" в виде пар:

"Наименование" <-> "Синоним".

Полный текст SQL-запроса приведен на следующем скриншоте.

Текст SQL-запроса для получения перечислений

Выполнение и обработка результата SQL-запроса осуществляется следующим программным кодом:

Выполнение SQL-запроса из 1С:Предприятия и обработка результата

Как мы видим, SQL-запрос выполняется с помощью COM-объекта "ADODB.Connection". Полученные строки выборки добавляются в список выбора элемента "Важность" (поле ввода) на форме. В результате выполнения данного программного кода мы можем выбирать на форме важность в соответствии со значениями перечислений (см. следующий скриншот).

Результат обработки SQL-запроса в 1С:Предприятие 8.x

Данный пример Вы можете посмотреть в тестовой конфигурации, ссылка на скачивание которой доступно в конце статьи.

Примечание о прямых запросах

Лицензионное соглашение от "1С" не позволяет делать прямые запросы к СУБД минуя объектный уровень платформы. По ссылке в ответе на вопрос №64 явно сказано о данном ограничении.

Причина, выдвигаемая компанией "1С", из-за которой установлено это ограничение: "Данное ограничение необходимо для обеспечения стабильности работы механизмов системы, осуществления поддержки и возможности перехода на новые версии "1С:Предприятия". В принципе логично, но не понятно одно: "Почему, если я купил СУБД, то не могу работать с ней ее же средствами?". А если я отключу платформу от СУБД, то тогда уже имею право на это?". Маразм.

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

Вывод

В статье был рассмотрен механизм хранения перечислений платформой 1С:Предприятие 8.x в базе данных и доступ к ним посредством прямого SQL-запроса.

Из всех объектов конфигурации, объект "Перечисление" имеет один из самых простых способов хранения на стороне СУБД, а запросы на их получение может сделать даже новичок в программировании на платформе. Тоже самое можно сказать и о программной работе с ними.

По поводу прямого SQL-запроса на получение значений перечисления - для удобство его можно перенести в хранимую процедуру. Тогда ее вызов будет более удобным.


comments powered by Disqus