Значение в невалидной таблице из предыдущей записи в цикле

Программирование на Атлантисе (VIP, FCOM, ARD), FastReport

Модераторы: m0p3e, edward_K, Модераторы

Ответить
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Значение в невалидной таблице из предыдущей записи в цикле

Сообщение Алексей »

В интерфейсе имеется цикл по корневой таблице, в котором выводим значения из подцепленных таблиц в отчёт (в эксель).
Почему то если таблица является невалидной (нет записи), то при обращении к её полям в отчет попадают значения из предыдущей записи...

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

Код: Выделить всё

  
_Loop ObjRemReestr 
{
  set Objrem_ := ObjRemReestr.nrec;
  Rereadrecord;
  ... 
  xlStWriteToMatrix(i,    7, anytable.vString   );
}
Вроде и set делается, который перерисовать должен логическую таблицу, и реридрекорд насильно... а всё равно, летят значения, которых фактически нет. Как с этим бороться, кроме как проверять перед каждый выводом валидность?
m0p3e
Местный житель
Сообщения: 1386
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Москва

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение m0p3e »

Вроде всегда так было.
Поэтому либо жесткая подцепка /==
Либо валидность проверять.

Код: Выделить всё

_Loop ObjRemReestr 
{
  If not IsValid(tn...)
    continue;
  set Objrem_ := ObjRemReestr.nrec;
  Rereadrecord;
  ... 
  xlStWriteToMatrix(i,    7, anytable.vString   );
}
Den
Местный житель
Сообщения: 1842
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Den »

Ну да. Всегда так и было.
Причем, помоему, isvalid вернет то что нужно если таблица "справа" подцеплена по уникальному ключу.
А еще есть FixRelations
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Алексей »

Хм... ясно.
Жесткая подцепка не покатит, т.к. всегда одна из 20-ти таблиц может не содержать значения и запись из корневой пропадёт.
Про "FixRelations" почитаю.
Спаисбо...
edward_K
Заслуженный деятель интернет-сообщества
Сообщения: 5185
Зарегистрирован: 29 мар 2005, 17:49
Откуда: SPB galaxy spb

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение edward_K »

1. ReReadRecord это медленно
2. В общем случае хватит
if isValid(#table)
{ вывод
}
else { вывод 0 }
но никак не continue;
3. Стал обращать внимание, что на 2012 MSSQL isValid не всегда корректно срабатывает, поэтому перешел к старому доброму getfirst - к тому же он с успехом заменяет ReReadRecord(#таблица).
Если нужен линейный список нескольких таблиц (типа как выводит select с повторением полей главной таблицы) можно завести переменную типа word. Выставить там все биты, а потом сбрасывать

Код: Выделить всё

wMask=1+2+4
if getfirst table1<> 0 wMask:=wMask-1;
if getfirst table1<> 0 wMask:=wMask-2;
if getfirst table3<> 0 wMask:=wMask-4;
do 
{
  вывод полей главной таблицы 
  if (wmask and 1)>0 
   { ....
     if getnext table1<> 0 wMask:=wMask-1;
   }
   if (wmask and 2)>0 
   { ....
     if getnext table2<> 0 wMask:=wMask-2;
   }
   if (wmask and 4)>0 
   { ....
     if getnext table3<> 0 wMask:=wMask-4;
   }
} while wMask<>0
Screw
Слесарь-системщик
Сообщения: 304
Зарегистрирован: 29 мар 2005, 17:49
Откуда: р.Беларусь, Унитарное предприятие "ТОП СОФТ"
Контактная информация:

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Screw »

Если дополнительная таблица подцеплена по уникальному ключу, то просто включите её в подзапрос для оператора цикла используя параметры оптимизации

Код: Выделить всё

  create view as from RootTable, LeafTable where ((RootTable.LeafRef == LeafTable.NRec));
  ...
  _loop RootTable (LeafTable) {
    if IsValid(tnLeafTable) {
      ...
    }
    
  }
При означенных условиях с помощью параметра оптимизации мы заставляем Атлантис доставлять данные корневого и подчинённого узлов одним запросом. IsValid проверяет, выполнялась ли доставка данных для узла и, если нет, то выполняет соответствующий запрос и возвращает статус операции, иначе - просто возвращает статус. В нашем случае работа метода сведётся к простой проверке статуса узла, поскольку попытка выборки данных уже была осуществлена (результаты частично уже лежат в кэшах драйвера; следующие порции доставляются и помещаются в кэши по мере необходимости).

ReReadRecord = ReReadRecord(CurTable) здесь совершенно не нужен? Более того, он может быть вреден для работы _loop.

Set здесь совершенно не нужен. Да и вообще, зачем запрос на перерисовку данных во время цикла, кроме как для "мультиков"? Тем более что Атлантис, ориентируясь на левую часть оператора присваивания (переменная ObjRem_), решит, что перерисовать нужно узел... tnNoTable и в нём же - взвести флаг наличия модификаций. Из обсуждения не видно, что все эти эффекты - ожидаемы и желательны.

Далее, если подчинённая таблица подцеплена по неуникальному ключу (как, к примеру, спецификация документа), то данные для неё в цикле ВСЁ РАВНО будут доставляться отдельным запросом. То есть, либо неявно - в вызове IsValid, либо явно - с помощью модификатора getXXXX. Разница заключается в том, что модификатор - это безоговорочный приказ, а метод выполняет попытку доставки только при необходимости. Только нужно учитывать, что по такой подцепке в подчинённой таблице может обнаружиться более, чем одна запись.

Код: Выделить всё

  create view as from RootTable, LeafTable where ((RootTable.NRec == LeafTable.RootRef));
  ...
  _loop RootTable {
    ...
    if getfirst LeafTable = tsOk {
      ...
    }
    // более годный вариант для многоразового применения  в рамках одной итерации
    if IsValid(tnLeafTable) {
      ...
    }
    
  }
Итак, валидность подцепленной таблицы НУЖНО проверять. И так было всегда.
Виталий
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Алексей »

Итак, валидность подцепленной таблицы НУЖНО проверять. И так было всегда.
Понятно :)

Set нужен, потому что цикл делаем по одной таблице, со своими ограничениями, и взяв nrec позиционируемся в другой таблице (синоним), к которой как раз подцеплены все остальные таблицы с нужными мне данными (в основном атрибуты объекта ремонта).

Но мысль уловил, будем проверять валидность или делать getfirst.
m0p3e
Местный житель
Сообщения: 1386
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Москва

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение m0p3e »

edward_K писал(а): 2. В общем случае хватит
if isValid(#table)
{ вывод
}
else { вывод 0 }
но никак не continue;
[/code]
continue то чем помешал? Компактно и читаемость текста лучше.
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Алексей »

Тем, что если подцепленных таблиц больше чем одна. В одной нет записи, а в других могут быть.
m0p3e
Местный житель
Сообщения: 1386
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Москва

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение m0p3e »

А continue то при чем? Если мне требуется пропустить запись без потомков в конкретно этой таблице?
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Алексей »

в какой этой? _loop по корневой таблицы, после невалидного листа continue переведёт корневую на следующую запись.
m0p3e
Местный житель
Сообщения: 1386
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Москва

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение m0p3e »

Алексей писал(а):в какой этой? _loop по корневой таблицы, после невалидного листа continue переведёт корневую на следующую запись.
Издеваемся? Проехали...
Screw
Слесарь-системщик
Сообщения: 304
Зарегистрирован: 29 мар 2005, 17:49
Откуда: р.Беларусь, Унитарное предприятие "ТОП СОФТ"
Контактная информация:

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Screw »

Алексей писал(а): Set нужен, потому что цикл делаем по одной таблице, со своими ограничениями, и взяв nrec позиционируемся в другой таблице (синоним), к которой как раз подцеплены все остальные таблицы с нужными мне данными (в основном атрибуты объекта ремонта).
Set для позиционирования не нужен, он вообще не для того предназначен. Особенно если навигация выполняется с помощью модификатора.
Если для подцепки используется переменная и вызов IsValid, то Атлантису не помешает маякнуть о том, что текущую запись в подцепленной таблице (если она есть) следует считать невалидной из-за изменения значения переменной. Делается это с помощью вызова FixRelations, которой в качестве параметра передаётся упомянутая переменная (Внимание! Передаётся сама переменная, а не номер поля, как в большинстве других методов интерфейса или ЛТ).

Код: Выделить всё

  create view 
    var
      LnkVar: comp;
    from RootTable, LeafTable where ((LnkVar == LeafTable.RootRef));
  ...
  _loop RootTable {
    ...
    LnkVar := RootTable.Nrec;
    if getfirst LeafTable = tsOk {
      ...
    }
    ...
    // или так
    LnkVar := RootTable.NRec;
    FixRelations(LnkVar); // а вот так упадёт: FixRelations(#LnkVar);
    if IsValid(tnLeafTable) {
      ...
    }   
Хотя особого смысла в использовании переменной нет: подцепки вида RootTable.NRec == LeafTable.RootRef вполне достаточно.
Виталий
Алексей
Местный житель
Сообщения: 2896
Зарегистрирован: 24 июн 2005, 12:12
Откуда: Иркутская область

Re: Значение в невалидной таблице из предыдущей записи в цик

Сообщение Алексей »

m0p3e писал(а):
Алексей писал(а):в какой этой? _loop по корневой таблицы, после невалидного листа continue переведёт корневую на следующую запись.
Издеваемся?
Нет, видимо мы не поняли друг друга.
Screw писал(а):
Алексей писал(а): Set нужен, потому что цикл делаем по одной таблице, со своими ограничениями, и взяв nrec позиционируемся в другой таблице (синоним), к которой как раз подцеплены все остальные таблицы с нужными мне данными (в основном атрибуты объекта ремонта).
Set для позиционирования не нужен, он вообще не для того предназначен. Особенно если навигация выполняется с помощью модификатора.
Если для подцепки используется переменная и вызов IsValid, то Атлантису не помешает маякнуть о том, что текущую запись в подцепленной таблице (если она есть) следует считать невалидной из-за изменения значения переменной. Делается это с помощью вызова FixRelations, которой в качестве параметра передаётся упомянутая переменная (Внимание! Передаётся сама переменная, а не номер поля, как в большинстве других методов интерфейса или ЛТ).

Код: Выделить всё

  create view 
    var
      LnkVar: comp;
    from RootTable, LeafTable where ((LnkVar == LeafTable.RootRef));
  ...
  _loop RootTable {
    ...
    LnkVar := RootTable.Nrec;
    if getfirst LeafTable = tsOk {
      ...
    }
    ...
    // или так
    LnkVar := RootTable.NRec;
    FixRelations(LnkVar); // а вот так упадёт: FixRelations(#LnkVar);
    if IsValid(tnLeafTable) {
      ...
    }   
Хотя особого смысла в использовании переменной нет: подцепки вида RootTable.NRec == LeafTable.RootRef вполне достаточно.
Про FixRelations ясно, спасибо. GetFirst как то привычней.
Но я так понял оператор Set и делает присвоение и getfirst одновременно. Это из доки
Оператор set в полной форме действует как обычный оператор присваивания и, кроме того, если <имя> - это поле таблицы, делается следующее:
эта таблица помечается как модифицированная, выполняется актуализация (изменение) всех таблиц, реляционно связанных с данным полем, и происходит перерисовка данного поля
Переменная нужна, т.к. интерфейс сложный и получает нрек объекта из другого встроенного и связанного интерфейса.
Ответить