Записная книжка программиста. Использование директивы «Разрешенные» Выбрать разрешенные
Запрос — это мощнейший инструмент, служащий для быстрого (по сравнению со всеми другими способами) получения и обработки данных, содержащихся в различных объектах информационной базы 1С.
Создание запроса
Запрос создается как отдельный объект, который имеет обязательный атрибут Текст , куда собственно и помещается сам запрос. Кроме этого, в запрос могут быть переданы различные параметры, необходимые для его выполнения. После того, как текст и параметры запроса заполнены, запрос необходимо выполнить и поместить результат выполнения в выборку или таблицу значений. Выглядит это все примерно так:
//Создаем запрос
Запрос =
новый Запрос;
//Заполняем текст запроса
Запрос.
Текст=
"Тут пишем текст запроса"
;
//Передаем в запрос параметры
Запрос.
УстановитьПараметр("ИмяПараметра"
,
ЗначениеПараметра)
;
//Выполняем запрос
Результат=
Запрос.
Выполнить()
;
//Выгружаем результат запроса в выборку
Выборка=
Результат.
Выбрать()
;
//Выгружаем результат запроса в таблицу значений
Таблица=
Результат.
Выгрузить()
;
//Последние действия можно объединить
Выборка=
Запрос.
Выполнить()
.
Выбрать()
;
//или
Таблица=
Запрос.
Выполнить()
.
Выгрузить()
;
Основы языка запросов 1С
Простейшие и наиболее часто применяемые запросы служат для получения данных из какого-то источника. Источником могут являться практически все объекты, содержащие какие-либо данные: справочники, документы, регистры, константы, перечисления, планы видов характеристик и т.д.
Из этих объектов с помощью запроса можно получать значения реквизитов, табличных частей, реквизитов табличных частей, изменений, ресурсов и т.д.
Для получения текста запроса часто бывает удобно пользоваться Конструктором запроса. Он вызывается при щелчке правой кнопкой в любом месте программного модуля.
Например, если необходимо получить значения всех реквизитов справочника Контрагенты , то запрос будет выглядеть так:
Запрос.
Текст =
"ВЫБРАТЬ
| *
|ИЗ
| Справочник.Контрагенты"
;
Если же нужно получить только отдельные реквизиты, то — так:
Запрос.
Текст =
"ВЫБРАТЬ
| Код,
| Наименование,
| Родитель
|ИЗ
| Справочник.Контрагенты"
;
Для получения такого текста запроса в Конструкторе запроса нужно выбрать соответствующие поля на вкладке Таблицы и поля.
Выбираемым в запросе элементам и источникам можно присваивать псевдонимы и использовать их в дальнейшем как в самом запросе, так и при работе с результатом. Кроме того, в запросе могут присутствовать поля с заранее определенным конкретным значением, или с рассчитываемым значением:
Запрос.
Текст =
"ВЫБРАТЬ
| Клиенты.Код КАК Номер,
| 1000 КАК ПолеСоЗначением
|ИЗ
;
Выборка = Запрос. Выполнить() . Выбрать() ;
Пока
Выборка.
Следующий()
Цикл
НомерКлиента =
Выборка.
Номер;
ИмяКлиента =
Выборка.
Имя;
Знач
=
Выборка.
ПолеСоЗначением;
КонецЦикла
;
Для задания псевдонимов служит вкладка Объединения/Псевдонимы в Конструкторе запросов.
Все выбранные элементы можно упорядочивать как в прямом, так и в обратном порядке. При этом можно выбирать один или несколько полей для упорядочивания. Вместе с упорядочиванием иногда бывает полезно выбрать только один или несколько первых элементов.
//Упорядочим клиентов по имени от А до Я и выберем первых 10
Запрос.
Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
|УПОРЯДОЧИТЬ ПО
| Имя"
;
//Выберем самого последнего по алфавиту клиента
Запрос.
Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты
|УПОРЯДОЧИТЬ ПО
| Имя УБЫВ"
;
Можно ограничить выборку элементов теми, на которые пользователь имеет права доступа. Или убрать из результата запроса повторяющиеся строки.
//Выборка разрешенных пользователю данных
Запрос.
Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты"
;
//Выборка неповторяющихся элементов
Запрос.
Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты"
;
Порядок задается на вкладке Порядок в Конструкторе запросов, количество выбираемых элементов, параметры разрешенности и повторяемости — на вкладке Дополнительно.
Объект конфигурации «роль» дает набор прав на операции (действия) над объектами конфигурации.
Роль «Полные права».
Это всего лишь роль (не предопределенная), в которой установлены флажки на все виды прав на все объекты конфигурации.
Отличие ее от остальных ролей – наличие права «Администрирование».
В случае создания хотя бы одного пользователя, система начинает проверять наличие права «Администрирование» — оно должно быть минимум у одного пользователя.
Ограничение доступа на уровне записей
Row Level Security (RLS) – ограничение на уровне записей.
Механизм ограничений доступа к данным позволяет управлять правами доступа не только на уровне объектов метаданных, но и на уровне объектов базы данных. Для ограничения доступа к данным могут быть использованы следующие объекты:
- роли,
- параметры сеанса,
- функциональные опции,
- привилегированные общие модули,
- ключевое слово РАЗРЕШЕННЫЕ в языке запросов.
Механизм предназначен для ограничения доступа к записям таблицы объектов метаданных по произвольным условиям, накладываемым на значения полей строк этих таблиц. Например, чтобы видеть записи только по «своим» контрагентам, организациям и т.д.
Техническая реализация ограничений доступа в 1С
1С формирует запрос к СУБД. Кластер серверов добавляет к запросу секцию ГДЕ, в которой содержится текст условия на ограничение доступа по RLS, затем этот запрос отправляется в СУБД, извлеченные данные возвращаются на клиент 1С.
Такой механизм будет работать при любом запросе из клиента:
- в отчетах,
- в динамических списках и в обычных формах списков
- в произвольных запросах.
Подобная реализация механизма сильно влияет на производительность.
Пути обхода ограничений доступа.
В больших ресурсоемких операциях (обработки перепроведения документов, например) часть кода можно выносить в привилегированные модули.
А) Привилегированный модуль — это общий модуль с флагом «Привилегированный» в свойствах.
Его особенность заключается в том, что код в нем исполняется без какого-либо контроля прав доступа, в том числе и RLS.
Б) Также привилегированный режим можно включить для модулей объектов документов . Это делается в свойствах документа, флаг
- Привилегированный режим при проведении
- Привилегированный режим при отмене проведения
В) Метод УстановитьПривилегированныйРежим()
Системная команда, позволяет сделать часть кода любого модуля привилегированной.
Со следующей строки кода будет действовать привилегированный режим исполнения.
Действовать он будет до строки отключения этого режима или до конца процедуры / функции
(Истина );
// любой код тут будет исполнен без контроля прав и RLS
УстановитьПривилегированныйРежим (Ложь ); // либо конец процедуры / функции
Количество включений привилегированного режима должно совпадать с количеством выключений. Однако если внутри процедуры или функции происходило включение привилегированного режима (один раз или более), но не происходило его выключение, то система автоматически выполнит выключение столько раз, сколько незавершенных включений было в покидаемой процедуре или функции
Если в процедуре или функции вызовов метода УстановитьПривилегированныйРежим (Ложь ) сделано больше, чем вызовов метода УстановитьПривилегированныйРежим (Истина ), то будет вызвано исключение
Функция ПривилегированныйРежим () возвращает Истина , если привилегированный режим еще включен, и Ложь , если он полностью выключен. При этом не анализируется количество установок привилегированного режима в конкретной функции.
Все вызванные процедуры и функции также будут исполняться в привилегированном режиме.
Также существует возможность стартовать привилегированный сеанс. Это сеанс, в котором привилегированный режим установлен с самого начала работы системы. При этом во время работы метод ПривилегированныйРежим () будет всегда возвращать Истина , а возможность отключить привилегированный режим не поддерживается. Стартовать привилегированный сеанс может только пользователь, которому доступны административные права (право Администрирование). Запуск сеанса можно выполнить с помощью ключа командной строки запуска клиентского приложения UsePrivilegedMode или параметра строки соединения с информационной базой prmod .
Закономерно возникает вопрос: Зачем тогда вообще настраивать ограничения доступа, если его можно так легко обойти?
Безопасный режим.
Да, можно написать внешнюю обработку с привилегированным режимом исполнения и выгрузить / испортить данные. Для предотвращения этого в системе есть метод глобального контекста
УстановитьБезопасныйРежим ().
Безопасный режим кроме прочего игнорирует привилегированный режим.
Его нужно устанавливать перед программным вызовом внешних обработок или экспортных процедур и функций из их модулей.
При выполнении запрещенных операций во время выполнения генерирует исключение.
Кроме этого, для пользователей можно выключить на уровне настройки ролей возможность интерактивного запуска внешних отчетов и обработок.
Настройка ограничения доступа
RLS можно настроить только для прав:
- чтение (select)
- добавление (insert)
- изменение (update)
- удаление (delete)
Для операций чтения и удаления объект, находящийся в базе данных, должен соответствовать ограничению доступа к данным.
Для операции добавления ограничению доступа к данным должен соответствовать объект, который планируется записать в базу данных.
Для операции изменения ограничению доступа к данным должен соответствовать объект как до изменения (чтобы объект был прочитан), так и после изменения (чтобы объект был записан).
Для всех остальных прав такой возможности нет.
Добавим новое ограничение для права «чтение» справочника «Номенклатура». Откроется список полей, для которых можно настроить добавляемое ограничение.
Это означает, что при попытке получить доступ к отмеченным флажками полям, ограничение сработает, а при попытке получить доступ к неотмеченным полям ограничение не сработает.
Если выбрать флаг «Прочие поля », ограничение будет настроено для всех полей таблицы, кроме полей, для которых ограничения заданы явным образом.
*Особенность: для прав добавление, изменение, удаление:
- Ограничение может быть настроено только для всех полей.
- Ограничение может быть только одно.
Для права «Чтение» можно настроить несколько условий, они будут объединяться логическим оператором «И».
В ограничениях на объекты базы данных следующих типов могут быть использованы не все поля основного объекта данных ограничения:
- в регистрах накопления ограничения доступа могут содержать только измерения основного объекта ограничения;
- в регистрах бухгалтерии в ограничениях можно использовать только балансовые измерения основного объекта ограничения
Если в условиях ограничения доступа к данным оборотного регистра накопления используются измерения, не входящие в итоги, то при обращении к виртуальной таблице оборотов не используются хранимые итоги и запрос выполняется полностью по таблице движений.
Механизм наложения ограничений доступа.
Любая операция над данными, хранимыми в базе данных, в «1С:Предприятии» в конечном счете приводит к обращению к базе данных с некоторым запросом на чтение или изменение данных. В процессе исполнения запросов к базе данных внутренние механизмы «1С:Предприятия» выполняют наложение ограничений доступа. При этом:
- Формируется список прав (чтение, добавление, изменение, удаление), список таблиц базы данных и список полей, используемых этим запросом.
- Из всех ролей текущего пользователя выбираются ограничения доступа к данным для всех прав, таблиц и полей, задействованных в запросе. При этом если какая-нибудь роль не содержит ограничений доступа к данным какой-нибудь таблицы или поля, то это значит, что в данной таблице доступны значения требуемых полей из любой записи. Иначе говоря, отсутствие ограничения доступа к данным означает наличие ограничения ГДЕ Истина .
- Получаются текущие значения всех параметров сеанса и функциональных опций , участвующих в выбранных ограничениях.
Для получения значения параметра сеанса или функциональной опции от текущего пользователя не требуется наличие права на получение этого значения. Однако если значение некоторого параметра сеанса не было установлено, то произойдет ошибка и запрос к базе данных выполнен не будет.
Ограничения, полученные из одной роли, объединяются операцией И .
Ограничения, полученные из разных ролей, объединяются операцией ИЛИ .
Построенные условия добавляются к SQL-запросам, с которыми «1С: Предприятие» обращается к СУБД. При обращении к данным со стороны условий ограничения доступа проверка прав не выполняется (ни к объектам метаданных, ни к объектам базы данных). Причем механизм добавления условий зависит от выбранного способа действия ограничений «все» или «разрешенные».
*Особенность : Если пользователю доступны несколько ролей с настроенными ограничениями на уровне записей к одному объекту, то в этом случае условия ограничений складываются логической операцией «ИЛИ ». Другими словами полномочия пользователя складываются.
Отсюда вытекает след вывод: не допускать пересечения условия ограничения доступа к одному объекту в разных ролях, т.к в этом случае сильно усложнится текст запроса и это повлияет на производительность.
Способ «Все».
При наложении ограничений способом «все» к SQL-запросам добавляются условия и поля так, чтобы «1С:Предприятие» могло получить информацию о том, были ли в процессе исполнения запроса к базе данных использованы данные, запрещенные для данного пользователя или нет. Если запрещенные данные были использованы, то инициируется аварийное завершение запроса из-за нарушения прав доступа.
Наложение ограничений доступа способом «все» схематически представлено на рисунке:
Способ «Разрешенные».
При наложении ограничений способом «разрешенные» к SQL-запросам добавляются такие условия, чтобы запрещенные текущему пользователю записи не оказывали влияния на результат запроса. Иначе говоря, при наложении ограничений в режиме «разрешенные» запрещенные данному пользователю записи считаются отсутствующими и на результат операции не влияют, что схематически представлено на рисунке:
Ограничения доступа к данным накладываются на объекты базы данных в момент обращения «1С:Предприятия» к базе данных.
В клиент-серверном варианте «1С:Предприятия» наложение ограничений выполняется на сервере «1С:Предприятия».
Однако эта опция (РАЗРЕШЕННЫЕ) не сработает в случае, если мы в запросе обратимся к таблице, для которой не настроены ограничения доступа, но в которой есть ссылки на строки таблицы с настроенными ограничениями. В этом случае результат запроса выдаст «<Объект не найден>…...» вместо значения ссылочного поля.
Если вы разрабатываете отчет или обработку с использованием запросов типовой или самописной конфигурации, всегда ставьте флаг «Разрешенные» , чтобы отчет работал под любым пользователем с любым набором прав.
В случае объектного чтения данных из базы нет возможности поставить флаг «Разрешенные». Поэтому нужно настраивать отборы для объектного чтения с учетом возможных ограничений прав доступа для пользователя. Средств получения только разрешенных данных в объектной технике не предусмотрено.
Важно, что если в запросе не указано ключевое слово РАЗРЕШЕННЫЕ, то все отборы, заданные в этом запросе, не должны противоречить ни одному из ограничений на чтение объектов базы данных, используемых в запросе. При этом если в запросе используются виртуальные таблицы, то соответствующие отборы должны быть наложены и на сами виртуальные таблицы.
Практика 1. Конструктор запросов в настройках RLS.
Составим текст секции «ГДЕ» в запросе к справочнику. Можно воспользоваться конструктором запросов.
Конструктор имеет урезанный вид.
Закладка «Таблицы»
Основная таблица будет таблицей объекта, для которого настраивается ограничение.
Можно также выбирать и другие таблицы и настраивать между ними различные связи на закладке «Связи».
Закладка «Условия»
Здесь настраиваются собственно условия ограничения доступа
Добавим условия на реквизит «Цена» справочника номенклатура для права на «чтение» ко всем полям таблицы.
«Номенклатура ГДЕ Номенклатура.Цена > 500»
Проверим, как сработает это простое правило. Таблица справочника содержит такие элементы:
После настройки ограничения доступа таблица покажет только элементы, удовлетворяющие условию:
Пропали также и группы. Изменим текст ограничения
«Номенклатура ГДЕ Номенклатура.Цена > 500
ИЛИ Номенклатура.ЭтоГруппа»
Ну вот теперь то, что нужно.
Если в настройке списка убрать отображение поля «код», будут выведены все элементы справочника, т.е. ограничение не сработало. Если поставить отображение поля «Код», ограничение будет работать.
При этом, несмотря на то, что элемент справочника виден в поле списка, его форму нельзя будет открыть, потому что настроено ограничение на реквизит. То же самое в произвольном запросе: при попытке получить «ограниченный» реквизит, будет ошибка доступа.
Если попытаться получить «ограниченный» реквизит программным образом, также будет вызвана ошибка доступа.
Более того, нельзя будет обратиться к любым полям объекта через ссылку, т.к при получении ссылки система считывает весь объект целиком, и если в нем есть «ограниченные» реквизиты, объект считан не будет.
Поэтому при программной работе с объектами БД нужно иметь в виду возможные ограничения на уровне записей и получать все нужные данные объекта запросом и затем помещать их в структуру или исполнять часть кода в привилегированном модуле.
После настройки ограничения доступа изменилось отображение строки в списке прав – она стала серой и появилась пиктограмма.
Ограничения при настройке доступа (RLS).
- Нет секции Итоги;
- Нельзя обращаться к виртуальным таблицам регистров;
- В явном виде нельзя использовать параметры;
- Во вложенных запросах могут использоваться любые>/span> средства языка запросов, кроме
:
- оператора В ИЕРАРХИИ;
- предложения ИТОГИ;
- результаты вложенных запросов не должны содержать табличные части>/span>;
- виртуальных таблиц , в частности ОстаткиИОбороты
Практика 2. Номенклатура с актуальной ценой.
Сделать ограничение доступа, если нужно выводить номенклатуру с актуальной ценой больше определенного значения, например, 100.
Решение:
Добавляем новое правило ограничения доступа для справочника «Номенклатура» на право «чтение».
Выбираем «прочие поля».
В конструкторе добавляем вложенный запрос. В нем выбираем таблицу регистра сведений «Цены номенклатуры».
Вкладки «порядок» нет – это особенность конструктора запросов для построения запроса ограничения доступа.
На вкладке «Дополнительно» ставим «первые 999999999», вкладка «порядок» появилась.
Настраиваем упорядочивание по полю «Период» по убыванию.
Затем настраиваем связь основной таблицы с вложенным запросом по ссылке.
Шаблоны ограничений доступа .
Практика 3. Ограничение на «контрагенты» по значению в константе.
Настроим ограничение доступа для справочника Контрагенты по значению, которое хранится в Константе.
Кроме этого, нужно настроить ограничение и для всех объектов, использующих справочник «Контрагенты» в реквизитах.
Решение
Для справочника «Контрагенты» для права «чтение» настроим ограничение, добавив в секцию «Условия» вложенный запрос к константе. Не забыть ЭтоГруппа.
Видим проблему, справочник Контрагенты фильтруется верно, а документы с реквизитом «Контрагент» отображаются все, некоторые с «битыми» ссылками в реквизите «Контрагент».
Теперь нужно настроить ограничение доступа для всех объектов, использующих ссылку на «Контрагенты». Найдем их сервисом «поиск ссылок на объект».
Скопируем и немного доработаем текст условия RLS из справочника «Контрагенты». Это нужно сделать столько раз, сколько найдено объектов.
Или использовать шаблон ограничений доступа, чтобы избежать проблем дублирования кода.
Шаблоны ограничений доступа настраиваются на уровне роли и могут использоваться для любого объекта в рамках редактируемой роли.
Можно вынести в шаблон любой кусок текста ограничения доступа. Вызов шаблона осуществляется через символ «#». Например, #ШаблонКонтрагент.
Через # в 1С пишутся инструкции препроцессору. В контексте исполнения настроек ограничений доступа платформа заменяет текст вызова шаблона на текст шаблона.
Вынесем в шаблон «ШаблонКонтрагент» текст после слова ГДЕ, кроме текста про ЭтоГруппа.
Параметры в шаблонах ограничений доступа.
Продолжим решение задачи 2.
Проблема заключается теперь в том, что основная таблица в справочнике называется «контрагент», в документе «Приходная накладная». Проверяемое поле в справочнике называется «ссылка», в документе – «Контрагент».
Изменим в тексте шаблона название основной таблицы на «#ТекущаяТаблица»
«#ТекущаяТаблица» — это предопределенный параметр.
И через точку укажем номер входного параметра – «.#Параметр(1)
«#Параметр» — это тоже предопределенное значение. Может содержать произвольное количество входных параметров. Обращение к ним происходит по порядковому номеру.
В тексте ограничения доступа для справочника укажем следующее:
Для документа следующее:
«РеализацияТоваров ГДЕ #ШаблонКонтрагент(«Контрагент»)»
При вызове шаблона ограничения доступа параметры в него передавать нужно только как Строка, т.е в кавычках.
Основная таблица — Номенклатура
Текст шаблона такой:
#ТекущаяТаблица ГДЕ #ТекущаяТаблица.#Параметр(1) = #Параметр(2)
Текст шаблона содержит часть текста на языке ограничения доступа к данным и может содержать параметры, которые выделяются при помощи символа «#» .
После символа «#» могут следовать:
- Одно из ключевых слов:
- Параметр, после которого в скобках указывается номер параметра в шаблоне;
- ТекущаяТаблица – обозначает вставку в текст полного имени таблицы, для которой строится ограничение;
- ИмяТекущейТаблицы – обозначает вставку в текст полного имени таблицы (как строковое значение, в кавычках), к которой применяется инструкция, на текущем варианте встроенного языка;
- ИмяТекущегоПраваДоступа – содержит имя права, для которого выполняется текущее ограничение: ЧТЕНИЕ/READ, ДОБАВЛЕНИЕ/INSERT, ИЗМЕНЕНИЕ/UPDATE, УДАЛЕНИЕ/DELETE;
- имя параметра шаблона – означает вставку в текст ограничения соответствующего параметра шаблона;
- символ «#» – обозначает вставку в текст одного символа «#» .
В выражении ограничения доступа могут содержаться:
- Шаблон ограничения доступа, который указывается в формате #ИмяШаблона(«Значение параметра шаблона 1», «Значение параметра шаблона 2»,...) . Каждый параметр шаблона заключается в двойные кавычки. При необходимости указания в тексте параметра символа двойной кавычки следует использовать две двойные кавычки.
- Функция СтрСодержит(ГдеИщем, ЧтоИщем) . Функция предназначена для поиска вхождения строки ЧтоИщем в строке ГдеИщем. Возвращает Истина в случае, если вхождение обнаружено и Ложь – в противном случае.
- Оператор + для конкатенации строк.
Для удобства редактирования текста шаблона на закладке Шаблоны ограничений в форме роли нужно нажать кнопку Установить текст шаблона. В открывшемся диалоге ввести текст шаблона и нажать кнопку ОК.
Их нельзя установить методом УстановитьПараметр() или чем-то подобным.
В качестве параметров в данном случае выступают:
- Параметры сеанса
- Функциональные опции
Чтение параметров сеанса в запросе ограничения доступа происходит в привилегированном режиме, т.е без контроля прав на операции с ними.
Практика 4. Доступ к «своим» контрагентам
Необходимо настроить ограничение доступа текущего пользователя к «своим» контрагентам.
Есть справочник «Пользователи», справочник «Контрагенты», документы с реквизитом «Контрагент».
Текущий пользователь должен видеть данные только по тем контрагентам, для которых с ним установлена связь.
Связь тоже нужно настроить.
Возможные варианты:
Установления связей пользователь + контрагент
- Реквизит в справочнике контрагенты
- Регистр сведений
Возможные решения задачи:
- Хранить пользователя в константе – плохой вариант, константа доступна всем пользователям.
- Хранить в параметрах сеанса фиксированный массив контрагентов текущего пользователя – не очень хороший вариант, контрагентов может быть много
- Хранить в параметрах сеанса текущего пользователя, затем запросом получать список «его» контрагентов – приемлемый вариант.
- Другие варианты.
Решение.
Создадим новый параметр сеанса «ТекущийПользователь» и пропишем его заполнение в модуле сеанса.
Создадим регистр сведений «Соответствие менеджеров и контрагентов»
Создадим новую роль и в ней новое ограничение доступа для документа «ПриходнаяНакладная».
В тексте запроса соединим основную таблицу с регистром сведений по Контрагент = Контрагент и Менеджер = &ТекущийПользователь. Вид соединения Внутреннее.
По возможности лучше избегать вложенных запросов в текстах ограничения доступа, т.к он будет выполняться при каждом чтении данных из этого объекта из БД.
Проверяем – ограничения работают
*Особенность : Если изменить список контрагентов пользователя в регистре ограничения доступа будут действовать сразу без перезапуска сеанса пользователя.
Практика 5. Дата запрета изменений.
Необходимо реализовать ограничение на редактирование данных раньше установленной даты запрета изменений.
Ограничивать нужно для пользователей.
Создадим регистр сведений «ДатыЗапретаИзменений» с измерением Пользователь, ресурс ДатаЗапрета.
Построим логику решения таким образом:
- если не указан пользователь, значит, запрет действует для всех пользователей
- если есть ограничение для всех пользователей и ограничение для конкретного пользователя, тогда действует ограничение для конкретного пользователя, а для остальных по общему принципу.
Очевидно, что такое ограничение можно настроить для объектов базы данных, которые имеют некоторую позицию на оси времени. Это могут быть
- Документы
- Периодические регистры сведений
Создадим новую роль «ОраниченияПоДатеЗапретаИзменений».
В ней для документа «ПриходнаяНакладная» для права «изменение» добавим новое ограничение доступа.
Настройку указываем для всех полей.
Текст ограничения такой:
ПриходнаяНакладная ИЗ Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ДатыЗапретаИзменений.ДатаЗапрета КАК ДатаЗапрета
ИЗ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
МАКСИМУМ(ДатыЗапретаИзменений.Пользователь) КАК Пользователь
ИЗ
РегистрСведений.ДатыЗапретаИзменений КАК ДатыЗапретаИзменений
ГДЕ
(ДатыЗапретаИзменений.Пользователь = &ТекущийПользователь
ИЛИ ДатыЗапретаИзменений.Пользователь = ЗНАЧЕНИЕ(Справочник.пользователи.ПустаяСсылка))) КАК ВЗ_Пользователь
ПО ДатыЗапретаИзменений.Пользователь = ВЗ_Пользователь.Пользователь) КАК ВложенныйЗапрос
ПО ПриходнаяНакладная.Дата > ВложенныйЗапрос.ДатаЗапрета
Проверяем – ограничение работает.
Использование инструкций препроцессору
#Если Условие1 #Тогда
Фрагмент запроса 1
#ИначеЕсли Условие2 #Тогда
Фрагмент запроса 2
#Иначе
Фрагмент запроса 3
#КонецЕсли
В условиях можно использовать логические операции (и. или, не и т.д) и обращение к параметрам сеанса.
Такой подход в контексте построения ограничений доступа удобен тем, что в зависимости от условий будет скомпилирован более короткий текст запроса. А более простой запрос меньше нагружает систему.
Минус заключается в том, что конструктор запроса с таким текстом работать не будет.
*Особенность :
В отличие от инструкций препроцессору встроенного языка в текстах ограничения доступа перед оператором Тогда нужно ставить решетку — #Тогда
Практика 6. Переключатель «Использовать RLS»
Дополним нашу систему ограничений переключателем, который включает/выключает использование ограничение на уровне записей.
Для этого добавим Константу и параметр сеанса с именем «ИспользоватьRLS».
Пропишем в Модуле сеанса установку значения параметра сеанса из значения константы.
Добавим во все тексты ограничения доступа такой код:
«#Если &ИспользоватьRLS #Тогда ….. #КонецЕсли»
Проверяем – все работает.
Однако, теперь после включения флага «использовать РЛС» изменения сразу в силу не вступят. Почему?
Потому что параметр сеанса устанавливается при запуске сеанса.
Можно сделать так, чтобы в момент записи нового значения константы переустанавливалось значение параметра сеанса, но это будет работать только для текущего сеанса пользователя. Другим пользователям необходимо выдавать сообщение о необходимости перезапустить систему.
Конец первой части.
20.09.2014
В языке запросов существует директива «Разрешенные». Она предназначена для отсеивания платформой записей, на которые у пользователя нет прав, при настройке ограничения на уровне записей базы данных.
Казалось бы, в запросах лучше всегда использовать данную директиву. Буду утверждать, что это не так. Так же, буду утверждать, что по возможности, стоит избегать её использования, вот почему.
Допустим, мы делаем отчет по взаиморасчетам физических лиц. У пользователя есть права на одну организацию, а в базе данных находится более одной организации и в базе данных включено ограничение на уровне записей. Так же, в базе данных есть регистр «Взаиморасчеты» с измерениями «Организация» и «Физлицо». Если в системе будет запрос
«Выбрать
Организация,
ФизЛицо
и он будет выполняться от имени пользователя с разрешением на одну организацию, то запрос не выполниться, при наличии записей других организаций в этом регистре. Случиться ошибка, а описание ошибки будет «У пользователя не достаточно прав для выполнения запроса!» и это действительно так, платформа не обманывает, поскольку у него нет прав на записи других организаций в этом регистре.
Что же делать в этом случае, использовать директиву «Разрешенные»? На мой взгляд не стоит. Необходимо всего лишь установить отбор по организации и пользователь сможет сформировать отчет. Запрос для отчета с компоновкой данных будет выглядеть так
«Выбрать
Организация,
ФизЛицо
{Выбрать
Организация
ФизЛицо}
Из РегистрНакопления.Взаиморасчеты
{Где
Организация
ФизЛицо}
Если пользователь будет выполнять запрос к таблице без отбора, то отчет не сформируется, и пользователь не узнает данных по другим организациям, а если он поставит отбор по своей организации, то сформирует с корректными данными.
Вы можете снова спросить - «Почему же не стоит применять директиву Разрешенные», это сразу накладывает отбор, убережет пользователя от не нужных ему сообщений!
На этот вопрос ответ будет такой - как в этом случае пользователь узнает, что в отчет попали все нужные данные. Допустим, ранее, этот пользователь работал под полными правами и ошибся и выбрал в документе физлицо из другой организации. Так же может быть ситуация, данные загружались - и в документы организации записалось подразделение другой организации (в ЗУП на них тоже накладываются ограничения по владельцу). В этом случае директива «Разрешенные» отсечет запрещенные данные без каких-либо сообщений пользователю, и он не узнает, что в отчет попало не все, что должно попасть.
Поэтому - не стоит повально вписывать данную директиву в запросы типовых конфигураций считая это ошибкой. Очень не рекомендуется это делать в запросах регламентированной отчетности. Так же не стоит это делать в других отчетах и документах, где нужна точность информации.
А как же все-таки избежать ошибки «падения» программы при не хватке прав?
Да очень просто, необходимо использовать команду «Попытка», вот пример:
Попытка
Запрос.Выполнить();
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
В отчетах с использованием СКД программный код исполнения отчета необходимо написать вручную, так же через попытку.
В результате, пользователь не получит не корректных данных и получит вменяемое сообщение об ошибке.
Можно ознакомиться с нюансами настройки RLS в обособленных подразделениях в нашей статье .
Язык запросов является одним из основополагающих механизмов 1С 8.3 для разработчиков. При помощи запросов можно быстро получить любые данные, хранящиеся в базе. Его синтаксис очень похож на SQL, но есть и отличия.
Основные достоинства языка запросов 1С 8.3 (8.2) перед SQL:
- разыменование ссылочных полей (обращение черед одну или несколько точек к реквизитам объектов);
- работа с итогами очень удобная;
- возможность создавать виртуальные таблицы;
- запрос можно писать как на английском, так и на русском языках;
- возможность блокировать данные для исключения взаимных блокировок.
Недостатки языка запросов в 1С:
- в отличие от SQL, в 1С запросы не позволяют изменять данные;
- отсутствие хранимых процедур;
- невозможность преобразования строки в число.
Рассмотрим наш мини учебник по основным конструкциям языка запросов 1С.
В связи с тем, что запросы в 1С позволяют лишь получать данные, любой запрос должен начинаться со слова «ВЫБРАТЬ». После этой команды указываются поля, данные из которых нужно получить. Если указать «*», то будут выбраны все доступные поля. Место, откуда будут выбираться данные (документы, регистры, справочники и прочее) указывается после слова «ИЗ».
В рассмотренном ниже примере выбираются наименования всей номенклатуры из справочника «Номенклатура». После слова «КАК» указываются псевдонимы (имена) для таблиц и полей.
ВЫБРАТЬ
Номенклатура.Наименование КАК НаименованиеНоменклатуры
ИЗ
Справочник.Номенклатура КАК Номенклатура
Рядом с командой «ВЫБРАТЬ» можно указать ключевые слова:
- РАЗЛИЧНЫЕ . Запрос будет отбирать только отличающиеся хотя бы по одному полю строки (без дублей).
- ПЕРВЫЕ n , где n – количество строк с начала результата, которые необходимо отобрать. Чаще всего такая конструкция используется совместно с сортировкой (УПОРЯДОЧИТЬ ПО). Например, когда нужно отобрать определенное количество последних по дате документов.
- РАЗРЕШЕННЫЕ . Данная конструкция позволяет выбирать из базы только те записи, которые доступны текущему пользователю. Баз использования этого ключевого слова пользователю будет выведено сообщение об ошибке при попытке обращения запроса к тем записям, доступа к которым у него нет.
Эти ключевые слова могут использоваться как все вместе, так и по отдельности.
ДЛЯ ИЗМЕНЕНИЯ
Это предложение блокирует данные для исключения взаимных конфликтов. Заблокированные данные не будут считываться из другого соединения до окончания транзакции. В данном предложении можно указывать конкретные таблицы, которые нужно заблокировать. В противном случае будут заблокированы все. Конструкция актуальна лишь для режима автоматических блокировок.
Чаще всего предложение «ДЛЯ ИЗМЕНЕНИЯ» используется при получении остатков. Ведь при одновременной работе нескольких пользователей в программе, пока один получает остатки, другой может их изменить. В таком случае полученный остаток будет уже не верен. Если же заблокировать данные этим предложением, то пока первый сотрудник не получит корректный остаток и не совершит с ним все необходимые манипуляции, второй сотрудник будет вынужден ждать.
ВЫБРАТЬ
Взаиморасчеты.Сотрудник,
Взаиморасчеты.СуммаВзаиморасчетовОстаток
ИЗ
РегистрНакопления.ВзаиморасчетыССотрудниками.Остатки КАК Взаиморасчеты
ДЛЯ ИЗМЕНЕНИЯ
ГДЕ (WHERE)
Конструкция необходима для наложения какого-либо отбора на выгружаемые данные. В некоторых случая получения данных из регистров разумнее прописывать условия отборов в параметрах виртуальных таблиц. При использовании «ГДЕ», сначала получаются все записи, и только потом применяется отбор, что значительно замедляет выполнение запроса.
Ниже приведен пример запроса получения контактных лиц с определенной должностью. Параметр отбора имеет формат: &ИмяПараметра (имя параметра произвольное).
ВЫБОР (CASE)
Конструкция позволяет указывать условия непосредственно в теле запроса.
В приведенном ниже примере «ДополнительноеПоле» будет содержать текст в зависимости от того проведен документ или нет:
ВЫБРАТЬ
ПоступлениеТиУ.Ссылка,
ВЫБОР
КОГДА ПоступлениеТиУ.Проведен
ТОГДА «Документ проведен!»
ИНАЧЕ «Документ не проведен…»
КОНЕЦ КАК ДополнительноеПоле
ИЗ
Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТиУ
СОЕДИНЕНИЕ (JOIN)
Соединения связывают две таблицы по определенному условию связи.
ЛЕВОЕ/ПРАВОЕ СОЕДИНЕНИЕ
Суть ЛЕВОГО соединения заключается в том, что полностью берется первая указанная таблица и к ней по условию связи привязывается вторая. Если записей, соответствующих первой таблице во второй не нашлось, то в качестве их значений подставляется NULL. Проще говоря, главной является первая указанная таблица и к её данным уже подставляются данные второй таблицы (если они есть).
Например, необходимо получить номенклатурные позиции из документов «Поступление товаров и услуг» и цены из регистра сведений «Цены номенклатуры». В данном случае, если цена у какой-либо позиции не найдена, вместо нее подставиться NULL. Из документа все позиции будут выбраны вне зависимости от того, есть ли на них цена или нет.
ВЫБРАТЬ
ПоступлениеТиУ.Номенклатура,
Цены.Цена
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТиУ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК Цены
ПО ПоступлениеТиУ.Номенклатура = Цены.Номенклатура
В ПРАВОМ все в точности да наоборот.
ПОЛНОЕ СОЕДИНЕНИЕ
Данный вид соединения отличается от предыдущих тем, что в результате будут возвращены все записи как первой таблицы, так и второй. Если по заданному условию связи в первой или второй таблице не найдено записей, вместо них будет возвращено значение NULL.
При использовании в предыдущем примере полного соединения будут выбраны все позиции номенклатуры из документа «Поступление товаров и услуг» и все последние цены из регистра «Цены номенклатуры». Значения не найденных записей, как в первой, так и во второй таблице будут равняться NULL.
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
Отличием ВНУТРЕННЕГО соединения от ПОЛНОГО является то, что если хотя бы в одной из таблиц не найдена запись, то запрос не выведет ее вообще. В результате будут выбраны только те номенклатурные позиции из документа «Поступление товаров и услуг», для которых в регистре сведений «Цены номенклатуры» есть записи, если в предыдущем примере заменить «ПОЛНОЕ» на «ВНУТРЕННЕЕ».
СГРУППИРОВАТЬ ПО (GROUP BY)
Группировка в запросах 1С позволяет сворачивать строки таблицы (группировочные поля) по определенному общему признаку (группируемым полям). Группировочные поля могут выводиться только с применением агрегатных функций.
Результатом следующего запроса будет список видов номенклатуры с максимальными ценами по ним.
ВЫБРАТЬ
,
МАКСИМУМ(Цены.Цена) КАК Цена
ИЗ
СГРУППИРОВАТЬ ПО
Цены.Номенклатура.ВидНоменклатуры
ИТОГИ
В отличие от группировки при использовании итогов выводятся все записи и уже к ним добавляются итоговые строки. Группировка выводит лишь обобщенные записи.
Итоги можно подводить по всей таблице целиком (с использованием ключевого слова «ОБЩИЕ»), по нескольким полям, по полям с иерархической структурой (ключевые слова «ИЕРАРХИЯ», «ТОЛЬКО ИЕРАРХИЯ»). При подведении итогов не обязательно использовать агрегатные функции.
Рассмотрим пример, аналогичный примеру выше с использованием группировки. В данном случае результат запроса вернет не только сгруппированные поля, но и детальные записи.
ВЫБРАТЬ
Цены.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
Цены.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК Цены
ИТОГИ
МАКСИМУМ(Цена)
ПО
ВидНоменклатуры
ИМЕЮЩИЕ (HAVING)
Данный оператор схож с оператором «ГДЕ», но используется только для агрегатных функций. Остальные поля, кроме используемых этим оператором, должны быть сгруппированы. Оператор «ГДЕ» не применим для агрегатных функций.
В рассмотренном ниже примере отбираются максимальные цены номенклатуры, если они превышают 1000, сгруппированные по виду номенклатуры.
ВЫБРАТЬ
МАКСИМУМ(Цены.Цена) КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК Цены
СГРУППИРОВАТЬ ПО
Цены.Номенклатура.ВидНоменклатуры
ИМЕЮЩИЕ
МАКСИМУМ(Цены.Цена) > 1000
УПОРЯДОЧИТЬ ПО
Оператор «УПОРЯДОЧИТЬ ПО» сортирует результат запроса. Для того, чтобы гарантированно выводить записи в постоянном порядке, используется АВТОУПОРЯДОЧИВАНИЕ. Примитивные типы сортируются по обычным правилам. Ссылочные типы сортируются по GUID.
Пример получения списка сотрудников, отсортированного по наименованию:
ВЫБРАТЬ
Сотрудники.Наименование КАК Наименование
ИЗ
Справочник.Сотрудники КАК Сотрудники
УПОРЯДОЧИТЬ ПО
Наименование
АВТОУПОРЯДОЧИВАНИЕ
Прочие конструкции языка запросов 1С
- ОБЪЕДИНИТЬ – результаты двух запросов в один.
- ОБЪЕДИНИТЬ ВСЕ – аналог ОБЪЕДИНИТЬ, но без группировки одинаковых строк.
- ПУСТАЯ ТАБЛИЦА – иногда используется при объединении запросов для указания пустой вложенной таблицы.
- ПОМЕСТИТЬ – создает временную таблицу для оптимизации сложных запросов 1С. Такие запросы называются пакетными.
Функции языка запросов
- ПОДСТРОКА обрезает строку с определенной позиции на указанное количество символов.
- ГОД…СЕКУНДА позволяют получить выбранное значение числового типа. Входным параметром является дата.
- НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА используются при работе с датами. В качестве дополнительного параметра указывается тип периода (ДЕНЬ, МЕСЯЦ, ГОД и т. п.).
- ДОБАВИТЬКДАТЕ позволяет прибавить или отнять от даты указанное время определенного типа (СЕКУНДА, МИНУТА, ДЕНЬ и т. п.).
- РАЗНОСТЬДАТ определяет разницу между двумя датами с указанием типа выходного значения (ДЕНЬ, ГОД, МЕСЯЦ и т. п.).
- ЕСТЬNULL заменяет отсутствующее значение на указанное выражение.
- ПРЕДСТАВЛЕНИЕ и ПРЕДСТАВЛЕНИЕССЫЛКИ получают строковое представление указанного поля. Применяются для любых значений и только ссылочных соответственно.
- ТИП, ТИПЗНАЧЕНИЯ используются для определения типа входного параметра.
- ССЫЛКА является логическим оператором сравнения для типа значения реквизита.
- ВЫРАЗИТЬ используется для преобразования значения к нужному типу.
- ДАТАВРЕМЯ получает значение типа «Дата» из числовых значений (Год, Месяц, День, Час, Минута, Секунда).
- ЗНАЧЕНИЕ в запросе 1С используется для указания предопределенных значений — справочников, перечислений, планов видов характеристик. Пример использования: «Где ЮрФизЛицо = Значение(Перечисление.ЮрФизЛица.ФизЛицо) «.
Конструктор запросов
Для создания запросов с 1С есть очень удобный встроенный механизм – конструктор запросов. Он содержит следующие основные вкладки:
- «Таблицы и поля» — содержит поля, которые необходимо выбрать и их источники.
- «Связи» — описывает условий для конструкции СОЕДИНЕНИЕ.
- «Группировка» — содержит описание конструкций группировок и суммируемых полей по ним.
- «Условия» — отвечает за отборы данных в запросе.
- «Дополнительно» — дополнительные параметры запроса, такие как ключевые слова команды «ВЫБРАТЬ» и пр.
- «Объединения/Псевдонимы» — указываются возможности объединения таблиц и задаются псевдонимы (конструкция «КАК»).
- «Порядок» — отвечает за сортировку результата запросов.
- «Итоги» — аналогична вкладке «Группировка», но применяется для конструкции «ИТОГИ».
Текст самого запроса можно просмотреть, нажав в левом нижнем углу на кнопку «Запрос». В данной форме его можно откорректировать вручную или скопировать.
Консоль запросов
Для быстрого просмотра результата запроса в режиме «Предприятие», либо отладки сложных запросов используется . В ней пишется текст запроса, устанавливаются параметры, и показывается его результат.
Скачать консоль запросов можно на диске ИТС, либо по .