Разминка для ума. Решение. Свободное скачивание!
Пока готовятся очередные материалы для участников нашего курса, исследуем одно интересное поведение платформы.
Мы решили, что скачивание видео будет доступно для всех!
Наш друг, программист Виктор Сергеевич (далее В.С.), написал простую обработку.
На форме размещены две таблицы – номенклатура и поставщики. При перемещении по номенклатуре должны обновляться поставщики.
Ничего сложного, правда?
Но по словам В.С. платформа ведет себя не адекватно при запуске этой обработки.
Помогите В.С. решить проблему. И, пожалуйста, оправдайте платформу 8.2, ведь она не такая плохая :)
К слову, разработчики описанное поведение ошибкой не считают.
Обработка доступна по ссылке.
Запускать ее можно на базе с домашними заданиями.
Раскрываем карты.
2. Решение.
ps. Распространение данного видео свободное, ссылка на наш сайт обязательна!
Хм… я где-то пропустил “одно средство, которое нам здорово поможет” в таком случае? :)
Речь шла о приеме выхода из вечного цикла :)
Ах вот оно что, ясно :)
А у меня была мысль проверять, меняется ли ТекущаяСтрока в Номенклатуре. Но мне показалось это слишком банальным. Думала, что Евгений предложит что-то очень оригинальное :) Но как известно, все гениальное – просто!
Точно :)
Я вчера так и не смог понять в чем ошибка. Оказалось всё настолько просто… На текст запроса даже не посмотрел :)
В обработке имеется ошибка в запросе. Пропущена точка. Как только ее поставить – платформа 8.2 работает нормально.
Кстати какой сейчас релиз последний? У меня стоит 8.2.11.235…
На последних релизах платформа ведет себя также.
1С:Предприятие 8.2 (8.2.12.78) слетает как миленькая ((((
При загрузке ТЗ Поставщики происходит перерисовка формы, система снова позиционируется на элементе динамического списка Номенклатура и происходит зацикливание.
Дело обстоит посерьезнее.
Закомментарьте строку с загрузкой таблицы значений, наблюдайте эффект :)
В описании события ПриАктивизацииСтроки высмотрел такую фразу: В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере
В моей базе у справочника контрагенты нет реквизита КонтрагентКод => запрос не выполняется.
Почему при ошибке в запросе (которая явно видна в конфигураторе) на моменте Запрос.Выполнить().Выгрузить() происходит вновь вызов обработчика ПриАктивизацииСтроки вместо вылетания обработки, пока не сообразил :( Подумаю дальше попозже )
А точнее обработчик вызывается уже на моменте выполнения запроса Запрос.Выполнить()… Хм…
А еще точнее обработчик вызывается при любой ошибке… Форма перерисовывается чтоли
Да. Точно, что-то типа того. При возникновении ошибки в Серверной процедуре явно происходит перерисовка формы, снова вызывается обработчик ПриАктивизацииСтроки.
Ошибка в безконтекстной серверной процедуре уже ничего не зацикливает.
Вот как-то так)) Плотней думать уже мало времени. Поработать тоже надо ))
2. Решение проблемы.
Как ни странно, несмотря на запрет серверного вызова в Синтакс-Помощнике, проблема решилась просто исправлением запроса, который содержал синтаксическую ошибку: вместо “ПоступлениеТоваровТовары.Ссылка.Контрагент.Код” нужно было написать “ПоступлениеТоваровТовары.Ссылка.Контрагент.Код“
Видимо, при работе обработчика ПриАктивизацииСтроки работает внутренняя обработка исключений средствами платформы, которая “закручивает” код в рекурсию… Или что-то еще?
Но тем не менее, проблема решается указанным способом!
1. Оправдание платформы 8.2
Достаточно посмотреть в Синтакс-Помощник, чтобы узнать, что “В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере.”
Таким образом, нарушив правило платформы, получили ошибку: после серверного вызова вновь вызывается обработчик ПриАктивизацииСтроки и система уходит в бесконечную рекурсию. И после n-ой итерации платформа просто вылетает.
Проверил на возникновении другой ошибки. В процедуре “ПолучитьПоставщиков” вызвал деление на ноль и та же ситуация))) Так же проверил при вызове ошибки на клиентской процедуре, ошибка вышла, а повторный вызов не произошел. Если создать кнопку на форме и по ней вызывать код в активации и при этом в форме указать текущим элементом любой элемен у которого есть событие активации, то при возврате ошибки с сервера сперва отработает событие активации а потом только выведется сообщение платформы! Очень интересно почему разработчики не считают это ошибкой?? Жду с нетерпением ответа)))
Вот это ключевой момент.
Ошибка может быть в любом месте, и платформа об этом будет молчать, просто свалиться..
Ошибка в запросе. Реквизита “КонтрагентКод” у документа ПоступлениеТоваров нет. Нужно написать так:
| ПоступлениеТоваровТовары.Ссылка.Контрагент.Код КАК Статус
Тогда работает.
не нужно реквизиты и перемененные одним именем называть… “Номенклатура” – корень всего зла :)))
Событие “ПриАктивизацииСтроки” вызывается раньше вывода сообщений об ошибке исполнения кода платформой)
На сколько я понял при непосредственной загрузке на сервере в реквизит данных происходит повторная активизация строки и, соответственно, зацикливание. Если же использовать РеквизитФормыВЗначение и ЗначениеВРеквизитФормы то все работает.
На счет ошибки запроса- так как у меня не было самой конфигурации (только обработка), то я в документ ПоступлениеТоваров добавил реквизит КонтрагентКод, посчитав что В.С. так и задумывал.
Напишите тогда в сервером методе Запрос.Печать();
Не работает?! У меня работает… Правда, я запустил ее под Управление небольшой фирмой и естественно отредактировал Запрос.
Я бы этому дяде с БОЛЬШИМИ ушами, уши бы..
Запрос нужно – корректно писать, или хотя-бы открывать конструктором – для проверки..
А по существу – я так понимаю, если вызываемая процедура не отрабатывает, обработчик возвращается в исходную процедуруи происходит – рекурсия/зацикливание?!..
И что-то мне подсказывает, что это из-за контекста – на сервере не валится, а возвращается на клиент..
Да, рекурсивные вызовы происходят, такие чудеса :)
ТаблицаФормы (FormTable)
ПриАктивизацииСтроки (OnActivateRow)
Синтаксис:
ПриАктивизацииСтроки()
Описание:
Вызывается при активизации строки таблицы.
Примечание:
В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере.
Обращаем внимание на примечание. :)
После каждого серверного вызова происходит данное событие. В итоге закливание.
Подходящего события для динамического списка не нашел, ограничение касается и других событий “при активации”.
Решение попробую найти уже завтра.
Как обещал свой вариант решения, вчера времени не было.
Чужие ответы не подсматривал, интересно будет сравнить.
Итак процедуры с компиляцией на сервере использовать нельзя, так как происходит зацикливание.
Нужно использовать функцию с директивой компиляции &НаСервереБезКонтекста, которая вернет массив контрагентов и их статусы.
На клиенте очищаем таблицу поставщиков и добавляем новые строки обходом массива который вернула наша функция.
Кроме этого была ошибка в тексте запроса, статус беру из контрагента Контрагент.СтатусКлиента.
Прикольно. Даже не подумал что если в процессе выполнения нет ошибки то зацикливания не проиходит.
Судя по всему, при вызове серверного метода из формы и выполнения в этом методе загрузки в таблицу значений на форме – форма обновляется и опять срабатывает событие ПриАктивизацииСтроки. Стек вызовов переполняется и платформа валится. Более того, в синтакс-помощнике в описании события ПриАктивизацииСтроки сказано, что нельзя здесь пользовать серверные методы
Ошибка ясно дело в запросе, но почему не выдается ошибка при исполнении запроса – сказать не могу. Также странно что после неудачного выполнения запроса событие ПриАктивизацииСтроки() вызывается заново. В порядке предположения – для каких-то методов формы отключен синтаксический контроль запросов (для скорости?) и в случае неудачного выполнения запроса 1С запускает этод метод заново на исполнение.
Оправдание 1С :
Совет : “Кури мануал”.
ПриАктивизацииСтроки (OnActivateRow)
Синтаксис:
ПриАктивизацииСтроки()
Описание:
Вызывается при активизации строки таблицы.
Примечание:
В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере.
P.S. Видимо при контестном серверном вызове производится генерация события “ПриАктивации строки” … а это приведет к зацикливанию (что и произошло у В.С.)
Как сделать правильно:
В данном случае лучше отказаться от использования “Таблицы значений” в пользу динамического списка
Текст запроса динамического списка “Поставщики”:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ПоступлениеТоваровТовары.Ссылка.Контрагент,
ПоступлениеТоваровТовары.Ссылка.Контрагент.Код КАК Статус
ИЗ
Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваровТовары
ГДЕ
ПоступлениеТоваровТовары.Номенклатура = &Номенклатура
Текст обработчика НоменклатураПриАктивизацииСтроки:
Поставщики.Параметры.Элементы[0].Значение = Элементы.Номенклатура.ТекущаяСтрока;
Поставщики.Параметры.Элементы[0].Использование = Истина;
P.S. Если же всетаки в обработчике “ПриАктивацииСтроки” нужна какая-то явная серверная отбработка, то можновоспользоваться бесконтекстным серверным вызовом.
Все-таки иногда нужна именно таблица значений.
ОК. Тогда нужен внеконтекстный серверный вызов. В данном случае можно получить массив структур (ключи структуры Контрагент, Статус) … для этого контест не нужен … заполнение же таблицы (“ДанныеФормыКоллекция”) можно произвести на стороне клиента.
PS. Данное решение работать будет … только вот получение массива структур … из результата запроса … имхо не очень изящно будет выглядеть … но пока красиве не придумал.
Изящно … это с динамическим списком …
Евгений, есть более красивое решение и стоит еще подумать ?
Есть еще одно решение. Уже скоро выложу :)
Согласно мастер группе от 02.07.2010 события “ПриАктивизацииСтроки” происходят при создании и обновлении формы. Можно объявить на клиенте пременную формы
&НаКлиенте
перем старт;
, при попаднии в событие “ПриАктивизацииСтроки” проверять переменную на Неопределено,
Если старт = Неопределено Тогда
старт = Ложь;
Возврат;
КонецЕсли;
В этом случае обработка запуститься, но любое движение мышью и…все, конец..
Не досмотрел, надо было сбросить флаг при ошибке выполнения запроса.
Вы имеете ввиду отсутствие “.” в тексте запроса?
ПоступлениеТоваровТовары.Ссылка.Контрагент.Код
Вообщем да.
Но проблема глубже.
Вопрос на размышление – как сделать, чтобы система не тормозила на больших списках.
Ведь если нажать и удерживать Down система при обращении к БД может подвисать.
Тут как вариант – создать кеш таблицу при открытии формы обработки. А потом при активизации отбирать из кеша… Хотя при создании формы запрос может быть довольно тяжелым..!?
Может, обрабатывать надо не документ, а его движения?
Движения конечно же лучше, но есть принципиально лучшее решение.
Пожалуй, запишу отдельное видео.
Думаю выполнил.
В запросе была ошибка не было точки перед
Код Как Статус
И в качестве условия думаю лучше было-бы выбрать в иерархии (&Номенклатура),
а не = &Номенклатура
попробовал выставить, изменил в своей базе реквизиты – обработка зработала
забыл наверное программист выставить у динамического списка основную таблицу – вот поле и не отображается
Точку автор обработки пропустил.
| ПоступлениеТоваровТовары.Ссылка.Контрагент.Код
Верно. Но как-то странно ведет себя платформа. Не находите? :)
Так вроде работает у меня эта обработка, когда точка есть.
Перемещаюсь по номенклатуре – справа контрагенты с кодом в статусе.
Пока, вроде, странного и не нахожу после исправления ошибки кода.
А до исправления ошибки платформа не вела себя странно? :)
Странно вела, конечно, так ошибка же была. Исправила – нормально стало.
На самом деле ситуация утрирована.
Реально было написано около 400 строк кода, и найти ошибки – задача не тривиальная.
Ну да, когда ошибки накладываются, эффекты бывают очень разные. Тут будешь и про платформу думать, и про версию, и про клиент-серверное взаимодействие.
ТаблицаФормы (FormTable)
ПриАктивизацииСтроки (OnActivateRow)
Синтаксис:
ПриАктивизацииСтроки()
Описание:
Вызывается при активизации строки таблицы.
Примечание:
В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере.
Наверно в этом проблема ….
Догадка верная, а что же делать если нужен сервеный вызов.
Как помочь В.С.?
Хотя здесь штука еще более интересная.
Ведь в приведенной обработке нет контекстных серверных вызовов.
Поставщиков динамическим списком сделать, а номенклатуру туда параметром передавать.
Это вариант.
Но иногда требуется именно ТЗ, например, чтобы менять статус поставщиков.
а слона то я и не заметил… это с точкой в запросе, а почему она дестввительно себя так вела ? не выкидывала ошибку запроса а просто зависала …?
ПС А когда продажи начнуться ?
Скоро разберу поведение системы.
Продажи – объявим сроки чуть позже.