Вычисляемые реквизиты детального набора данных

10 15

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

Для того, чтобы добавить вычисляемый реквизит в главный набор данных (т.е. в карточку) надо воспользоваться функцией СпрИзмНабДан(), позволяющей модифицировать SQL-запрос получения набора данных с сервера и добавить в него свои реквизиты. Хороший пример - как это делается можно, опять же, посмотреть в РКК в событии "Набор данных / Открытие".

С реквизитами карточки в целом все просто. Сложности могут возникнуть только с формированием дополнений к SQL-запросу, но, вооружившись знанием T-SQL и Profiler с ними можно справиться. С реквизитами детальных наборов данных (т.е. табличными реквизитами) все несколько хитрее.

Дело в том, что при открытии набора данных подгружается не весь справочник, а только те данные, которые отображаются в форме-списке (плюс несколько системных вроде ИД). Табличные реквизиты туда вытащить нельзя, поэтому и загружать их сразу для всех записей в этом событии не имеет смысла. Все реквизиты записи загружаются только при открытии карточки, т.е. в событии "Карточка / Открытие".

Соответственно, если у нас есть вычисляемые табличные реквизиты, то вычислить их мы можем в событии открытия карточки. Итак, мы имеем данные, которые хотим добавить в реквизит. Записываем их туда кодом на ISBL. Получаем искомый результат - данные в карточке есть. Но мы изменили карточку, поэтому набор данных перешел в состояние "Изменение". И при открытии записи пользователь всегда видит активную кнопку "Сохранить", а при закрытии его предупреждают, что запись надо сохранить. Хотя он никаких изменений не делал.

Мне известно 2 способа борьбы с этим "злом". Первый - сохранять карточку при ее открытии. Но этот способ нехорош тем, что затормозит открытие карточки, а так же при каждом открытии будет добавлять запись в истории об изменении карточки. Кроме того, пользователь может и не иметь прав на сохранение этой записи, тогда этот способ вообще не будет работать.

Второй способ - воспользоваться недокументированными функциями IS-Builder - DisableModified(IDataSet) и EnableModified(IDataSet). Конечно, недокументированные функции это плохо, риск что она перестанет работать есть при каждом обновлении, но если нужны вычисляемые табличные реквизиты, то недокументированная функция - меньшее из зол. Буду рад, кстати, если кто-нибудь подскажет более правильный способ для решения этой задачи.

Итак, недокументированные функции. DisableModified(IDataSet) устанавливает запрет на проверку Modified набора данных, то есть  набор данных не будет считаться изменившимся, даже если в нем что-то изменилось. Функция EnableModified(IDataSet) возвращает проверку. Вычисляемый реквизит табличной части я заполняю так:

// отключить проверку, если запись не вновь созданная
if not Object.Inserted
  DisableModified(Object.DataSet)
endif
     
// заполнить реквизит ISBGroupThresholdKind тестовыми значениями
DS = Object.DetailDataSet(1)
while DS.RecordCount > 0
  DS.Delete
endwhile
i = 1
while i < 10
  DS.Insert
  DS.ISBGroupThresholdKind = 'Строка ' & i
  i = i + 1
endwhile
   
// включить проверку обратно
if not Object.Inserted     
  EnableModified(Object.DataSet)
endif       
Важные примечания:

  • в качестве аргументов у функций надо указывать главный набор данных, а не детальный;
  • работает как для справочников, так и для документов;
  • надо проверять, что запись не вновь создаваемая (проверка if not Object.Inserted). Для вновь создаваемой записи вызывать функции нельзя, иначе запись не сохранится;
  • метод применим только для реквизитов детальных разделов, для главного раздела надо пользоваться СпрИзмНабДан();
  • проверял на версиях IS-Builder 7.6.3 и 7.7. Функции не документированные, могут вдруг начать работать по-другому после обновления (а то и вообще исчезнуть), поэтому к их использованию стоит прибегать только когда нет других вариантов.
10
Авторизуйтесь, чтобы оценить материал.
1
Дмитрий Тарасов

Опять недокументированные функции Улыбка

Сколько же их там еще осталось таких, о которых мы до сих пор не знаем?!

Огласите весь список пожалуйста!!! Улыбка

Денис Баранов

Оглашаю по мере появления ситуаций, не решаемых обычными путями. Улыбка Тогда приходится пытать разработчиков платформы на предмет чего-нибудь экзотического, что мне бы подошло.

Александр Гуртяков

как-то пытался использовать эти скрытые возможности при разработке. На тот момент не знал, что они применимы только для детальных разделов. Я применял для главных и наблюдал следующие грабли:во первых применять эти функции нужно было в обратном порядке; во вторых иногда случалось, что последующие изменения карточки не приводили к "активации" кнопки сохранить.

А можно подробнее про то как использовать СпрИзмНабДан() для аналогичных целей.

Денис Баранов
А можно подробнее про то как использовать СпрИзмНабДан() для аналогичных целей.

Допустим, есть в главном разделе вычисляемый реквизит. Чтобы IS-Builder смог отобразить его значение, поле, соответствующее этому реквизиту, должно присутствовать в SQL-запросе, который посылается на сервер при открытии справочника как в режиме списка, так и при открытии карточки отдельной записи справочника. Просто так этот запрос состоит только из тех реквизитов, значения которых хранятся на сервере (т.е. не вычисляемых). Соответственно, для наших целей надо этот запрос модифицировать, добавить к нему поле, соответствующее вычисляемому реквизиту (в AddSelect) и вычисление его (в AddFrom и AddWhere). Наглядный пример есть в РКК.

 

 

Андрей Манаков
Наглядный пример есть в РКК.
А как быть тем, у кого РКК изначально нет и не было? (есть и такие)
Добавить
Наглядный пример
к материалу думаю совсем не помешает ;)
Руслан Бапин

Всем привет!

Проверили на IS-Builder 7.8 - не работает :(

Денис Баранов

Проверил на 7.8.3.1046 и 7.9.2.2305 - работает.

Алексей Язынин
А как быть тем, у кого РКК изначально нет и не было? (есть и такие)
А доступ к инструменту разработчика есть? В компоненте "Типы справочников" справочник "Регистрационно-контрольные карточки" отсутствует?
Андрей Манаков
В компоненте "Типы справочников" справочник "Регистрационно-контрольные карточки"
хм... хоть сам справочник и не доступен, события он все таки показывает. Спасибо.
Михаил Сергеев

Может кто подтвердить, что в 5.0 работает? А то у меня что- то не получается с детальным разделом.

Марина Котусева

Что-то не работает: состояние отображается Просмотр, но при этом кнопки Сохранить активны и при закрытии предлагает сохранить запись.
При этом в историю такие "псевдосохранения" не попадают.

Михаил Сергеев
состояние отображается Просмотр, но при этом кнопки Сохранить активны и при закрытии предлагает сохранить запись.

Спасибо, Марина.

Мне даже такого поведения не удалось добиться...  Может, конечно, эксперимент не чистый... DisableModified(Object.DataSet) "работает" (ваше поведение), только если реквизиты в Показ/Открытие заполнять? Я хотел в действии его использовать, которое добавит строку.

Марина Котусева

Столкнулась с такой задачей на практике и сама себя поправлю: работает без проблем на событии Запись.Открытие. Кривовато работало на Форме.Показ. Версия 5.0.0.12, IS 7.11.0.2506

Николай Бурдаков

Добрый день! Я попробовал 2-ой способ, но что-то сомневаюсь. А как можно сохранить карточку при открытии справочника? Через набор данных?

Эдуард Исабекян

Может кому-то пригодится еще один способ:

Можно воспользоваться методами IDataSet.AddSelect и IRequisiteFactory.CreateRequisite, в справке они описаны. Воспользоваться ими можно в событии Открытие набора данных. Методы вызывать у объекта, Object.DetailDataSet(i).
При этом есть нюансы:

  1. Для отображения на форме в таблицу должен быть добавлен несохраняемый реквизит детального раздела нужного типа.
  2. В AddSelect нужно указывать другое (относительно п.1) имя поля, которое еще не используется в реквизитах детального раздела.
  3. В CreateRequisite в качестве имени нужно передавать имя реквизита из п.1, а имя поля из п.2.

Если нужно не просто считать значения в реквизитах, а показывать полностью "виртуальные" строки детального раздела, то этого можно достичь с помощью AddJoin/AddWhere, но тогда обязательно нужно запрещать добавлять/удалять строки, и не отображать в таблице хранимых реквизитов. Если кому-нибудь будет интересно, могу отдельно написать.

Авторизуйтесь, чтобы написать комментарий