Страница 1 из 1
Значение в невалидной таблице из предыдущей записи в цикле
Добавлено: 07 окт 2016, 12:24
Алексей
В интерфейсе имеется цикл по корневой таблице, в котором выводим значения из подцепленных таблиц в отчёт (в эксель).
Почему то если таблица является невалидной (нет записи), то при обращении к её полям в отчет попадают значения из предыдущей записи...
Не хочется перед выводом данных в отчет каждый раз проверять таблицу на валидность... раньше такого не замечал, но в последнее время сюрпризы атлантиса появляются всё чаще и чаще...порой не знаешь откуда прилетит нежданчик...
Код: Выделить всё
_Loop ObjRemReestr
{
set Objrem_ := ObjRemReestr.nrec;
Rereadrecord;
...
xlStWriteToMatrix(i, 7, anytable.vString );
}
Вроде и set делается, который перерисовать должен логическую таблицу, и реридрекорд насильно... а всё равно, летят значения, которых фактически нет. Как с этим бороться, кроме как проверять перед каждый выводом валидность?
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 07 окт 2016, 12:46
m0p3e
Вроде всегда так было.
Поэтому либо жесткая подцепка /==
Либо валидность проверять.
Код: Выделить всё
_Loop ObjRemReestr
{
If not IsValid(tn...)
continue;
set Objrem_ := ObjRemReestr.nrec;
Rereadrecord;
...
xlStWriteToMatrix(i, 7, anytable.vString );
}
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 07 окт 2016, 14:34
Den
Ну да. Всегда так и было.
Причем, помоему, isvalid вернет то что нужно если таблица "справа" подцеплена по уникальному ключу.
А еще есть FixRelations
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 07 окт 2016, 15:43
Алексей
Хм... ясно.
Жесткая подцепка не покатит, т.к. всегда одна из 20-ти таблиц может не содержать значения и запись из корневой пропадёт.
Про "FixRelations" почитаю.
Спаисбо...
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 07 окт 2016, 17:15
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
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 07 окт 2016, 18:48
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) {
...
}
}
Итак, валидность подцепленной таблицы НУЖНО проверять. И так было всегда.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 08 окт 2016, 13:35
Алексей
Итак, валидность подцепленной таблицы НУЖНО проверять. И так было всегда.
Понятно
Set нужен, потому что цикл делаем по одной таблице, со своими ограничениями, и взяв nrec позиционируемся в другой таблице (синоним), к которой как раз подцеплены все остальные таблицы с нужными мне данными (в основном атрибуты объекта ремонта).
Но мысль уловил, будем проверять валидность или делать getfirst.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 09 окт 2016, 09:49
m0p3e
edward_K писал(а):
2. В общем случае хватит
if isValid(#table)
{ вывод
}
else { вывод 0 }
но никак не continue;
[/code]
continue то чем помешал? Компактно и читаемость текста лучше.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 09 окт 2016, 20:26
Алексей
Тем, что если подцепленных таблиц больше чем одна. В одной нет записи, а в других могут быть.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 10 окт 2016, 10:49
m0p3e
А continue то при чем? Если мне требуется пропустить запись без потомков в конкретно этой таблице?
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 10 окт 2016, 15:28
Алексей
в какой этой? _loop по корневой таблицы, после невалидного листа continue переведёт корневую на следующую запись.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 10 окт 2016, 16:18
m0p3e
Алексей писал(а):в какой этой? _loop по корневой таблицы, после невалидного листа continue переведёт корневую на следующую запись.
Издеваемся? Проехали...
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 10 окт 2016, 17:01
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 вполне достаточно.
Re: Значение в невалидной таблице из предыдущей записи в цик
Добавлено: 11 окт 2016, 06:23
Алексей
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 в полной форме действует как обычный оператор присваивания и, кроме того, если <имя> - это поле таблицы, делается следующее:
эта таблица помечается как модифицированная, выполняется актуализация (изменение) всех таблиц, реляционно связанных с данным полем, и происходит перерисовка данного поля
Переменная нужна, т.к. интерфейс сложный и получает нрек объекта из другого встроенного и связанного интерфейса.