AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 02.09.2021, 08:47   #1  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
как обойти ошибку - запись не выбиралась для обновления
Привет всем.
При выполнении такого джоба:
X++:
static void job123(Args _args)
{
	...
	void updateFieldValue(Common _common, FieldId _fieldId, anytype _value)
	{
		...
		try
		{
			ttsBegin;
			_common.selectForUpdate(true);
			_common.(_fieldId) = _value;
			_common.doUpdate();
			ttsCommit;
		}
		catch
		{
			ttsAbort;
		}
		...
	}
	...
	;
	
	...
	updateFieldValue(APMParameters::find(), fieldnum(APMParameters, Field1), valueField1);
	...
}

генерируется ошибка:

Цитата:
Невозможно отредактировать запись в Параметры (APMParameters).
Операция не может быть завершена, так как запись не выбиралась для обновления. Используйте TTSBEGIN/TTSCOMMIT наряду с выражением FORUPDATE.
Попытка изменения записи в таблице "APMParameters", которая не выбрана для изменения (RecId = 5637144576). [W-0108]

(S)\Classes\xRecord\doUpdate
(C)\Jobs\job123 - line 77

Мне получилось ее обойти так:
X++:
static void job123(Args _args)
{
	...
	void updateFieldValue(Common _common, FieldId _fieldId, anytype _value)
	{
		...
		try
		{
			//ttsBegin; // <-- убираем
			_common.selectForUpdate(true);
			_common.(_fieldId) = _value;
			_common.doUpdate();
			//ttsCommit; // <-- убираем
		}
		catch
		{
			ttsAbort;
		}
		...
	}
	...
	;
	
	...
	ttsBegin; // <-- добавляем
	updateFieldValue(APMParameters::find(), fieldnum(APMParameters, Field1), valueField1);
	ttsCommit; // <-- добавляем
	...
}


Вопросы:
1. возможно как то обойти данную ошибку но оставив ttsBegin/ttsCommit в методе updateFieldValue ?

2. Заметил что такая ошибка генерируется только для изменения данных у этой таблицы - APMParameters.
Если такое же выполнять для других таблиц, например: RassetParameters, CompanyInfo таких ошибок нет.
Не подскажете почему для одних таблиц нет ошибки а для APMParameters ошибка при вызове doUpdate()?

Последний раз редактировалось oleggy; 02.09.2021 в 08:52.
Старый 02.09.2021, 09:38   #2  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,317 / 3547 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Метод _common.selectForUpdate(true); должен выполняться до выборки данных.
Т.е. сначала _common.selectForUpdate(true);
А потом - select * from common.

Приведенный пример - излюбленный способ тех разработчиков, которым не хочется делать лишний select, а хочется уже после выборки либо обновлять, либо не обновлять запись (сам таким когда-то был - знаю). База данных так не работает. Ей нужно знать до выборки - блокировать ли записи или нет на обновление.
Поэтому правильное решение - перестроить код так, чтобы вызов метода selectForUpdate был бы ДО оператора выборки данных.
Конструкция, приведенная у Вас - может работать (ядро АХ все-таки старается) - но могут быть разные глюки - либо с блокировками при многопользовательской работе, либо с ошибками как у Вас, либо еще какие-то ошибки
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 02.09.2021 в 09:41.
За это сообщение автора поблагодарили: SRF (1), oleggy (1).
Старый 02.09.2021, 09:57   #3  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
Посмотрите по ключевому слову OCCEnabled, https://docs.microsoft.com/en-us/dyn...rrency-control

Для табличек у которых OCCEnabled = yes, ваш код будет работать, для тех у которых No не будет, им нужна явная выборка в транзакции.

Можно сделать примерно так, но получите дополнительное чтение в БД.

X++:
ttsbegin;
_common.selectForUpdate(true); 
_common.reread();
_common.(_fieldId) = _value;
_common.doUpdate();
ttscommit;
__________________
Sergey Nefedov

Последний раз редактировалось SRF; 02.09.2021 в 10:03.
За это сообщение автора поблагодарили: EVGL (5), sukhanchik (2), S.Kuskov (2), oleggy (1).
Старый 02.09.2021, 10:03   #4  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
А потом - select * from common.
А как сделать select для common таблицы?
Если известна recId записи и tableId этой таблицы.
Подскажите подход.

Цитата:
Сообщение от SRF Посмотреть сообщение
Можно сделать примерно так, но получите дополнительное чтение в БД.

X++:
ttsbegin;
_common.selectForUpdate(true); 
_common.reread();
_common.(_fieldId) = _value;
_common.doUpdate();
ttscommit;
К сожалению не сработало.
Старый 02.09.2021, 10:09   #5  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от oleggy Посмотреть сообщение
К сожалению не сработало.
А что значит не сработало?
Осталась та же самая ошибка? Появилась новая? Запись не обновилась?

Приведённый код точно рабочий. Пользуюсь таким давно. Проблем замечено не было
Старый 02.09.2021, 10:12   #6  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
А попробуйте вместо reread сделать

select _common where _common.recid == _common.recId;
__________________
Sergey Nefedov
Старый 02.09.2021, 10:21   #7  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
А что значит не сработало?
Осталась та же самая ошибка? Появилась новая? Запись не обновилась?

Приведённый код точно рабочий. Пользуюсь таким давно. Проблем замечено не было
Да, такая же ошибка, я проверил, для таблиц с OCCEnabled = No, reread не помогает, для них надо делать новый запрос в БД, видимо текущий курсор изменить уже нельзя, а нужно создавать новый.
__________________
Sergey Nefedov
Старый 02.09.2021, 10:33   #8  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Получилось только так:

X++:
static void job123(Args _args)
{
	...
	void updateFieldValue(Common _common, FieldId _fieldId, anytype _value)
	{
                DictField   dictField;
                DictTable   dictTable = new DictTable(_common.tableId);
                Common      common;
                ;
		...
		try
		{
			ttsBegin;
			common = dictTable.makeRecord();
			common.selectForUpdate(true);
			select common
				where common.RecId == _common.RecId;
			common.(_fieldId) = _value;
			ttsCommit;
		}
		catch
		{
			ttsAbort;
		}
		...
	}
	...
	;
	
	...
	updateFieldValue(APMParameters::find(), fieldnum(APMParameters, Field1), valueField1);
	...
}
За это сообщение автора поблагодарили: sukhanchik (2), SRF (1).
Старый 02.09.2021, 10:40   #9  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
А при такой конструкции ошибка ?

X++:
ttsbegin;
_common.selectForUpdate(true); 
select _common where _common.recid == _common.recId;
_common.(_fieldId) = _value;
_common.doUpdate();
ttscommit;
__________________
Sergey Nefedov
Старый 02.09.2021, 10:41   #10  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от SRF Посмотреть сообщение
А попробуйте вместо reread сделать
select _common where _common.recid == _common.recId;
Причем этот запрос не работал. Та же ошибка.

Потом я создал локальную common и написал так.
X++:
select common 
    where common.TableId == _common.TableId 
        && common.RecId == _common.RecId;
И тоже не сработало. Что странно. Я в common не силен. Запись не выбиралась почему то.
Старый 02.09.2021, 10:56   #11  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Ну надежды на то что сработает условие _common.recid == _common.recId нет и не может быть. Это как масло масленое. А то что common нужно инициализировать (типизировать) перед использованием в принципе логично. Иначе система не будет знать к какой таблице делать запрос и дополнительно условие по TableId здесь не спасает (в SQL нет такого понятия как запрос сразу ко всем таблицам).

Не понятно почему не сработал reread
За это сообщение автора поблагодарили: SRF (2).
Старый 02.09.2021, 11:26   #12  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,317 / 3547 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от oleggy Посмотреть сообщение
А как сделать select для common таблицы?
Если известна recId записи и tableId этой таблицы.
Подскажите подход.
Вариант 1
X++:
TableId     myTableId;
RecId       myRecId;
DictTable  dictTable = new DictTable(myTableId);
Common  myRecord;

myRecord = dictTable.myRecord();
select myRecord
where myRecord.RecId == myRecID;
Вариант 2
X++:
TableId     myTableId;
RecId       myRecId;
Query       query;
QueryBuildDataSource qbds;
QueryRun                     qr;

query = new Query();
qbds = query.addDataSource(myTableId);
qbds.addRange(fieldnum(Common, RecId)).value(queryvalue(myRecId));
qr = new QueryRun(query);
if (qr.next())
{
      myRecord = qr.getNo(1);
}
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 02.09.2021 в 11:33.
Старый 02.09.2021, 12:31   #13  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Ну надежды на то что сработает условие _common.recid == _common.recId нет и не может быть. Это как масло масленое
Хотя никто не запрещает сделать так
X++:
recId = _common.recid;
select forupdate _common where _common.recid == recId;

И по сути это тоже самое что и _common.reread(). Интересно сработает?

Последний раз редактировалось S.Kuskov; 02.09.2021 в 12:36.
Старый 02.09.2021, 18:51   #14  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Интересно, не встречал проблем с работой reread (ну конечно, если к этому моменту запись не удалена).
Там в вызове, случайно, нет какого-либо фиксирования, типа common.data() ?
Старый 03.09.2021, 09:22   #15  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Хотя никто не запрещает сделать так
X++:
recId = _common.recid;
select forupdate _common where _common.recid == recId;
И по сути это тоже самое что и _common.reread(). Интересно сработает?
Сегодня решил проверить. Да сработало.

После этого решил проверить:
X++:
_common.reread()
И сработало. Я не поверил ведь вчера оно не срабатывало.
Зашел на другой терминал, начал выполнять - не сработало. Вернулся на первоначальный терминал и теперь и там не работает.

Потом решил проверить это:
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Ну надежды на то что сработает условие _common.recid == _common.recId нет и не может быть. Это как масло масленое.
Все работает. Не знаю почему она вчера у меня не отрабатывала. Сегодня работает.

После этого я снова решил проверить:
X++:
_common.reread()
И снова заработало. Очень странно.

Последний раз редактировалось oleggy; 03.09.2021 в 09:24.
Старый 03.09.2021, 09:35   #16  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Я понял из за чего ошибка генерируется у меня.
Данный код отрабатывает корректно:
X++:
ttsBegin;
select forupdate _common
	where _common.recid == _common.recid;
_common.(_fieldId) = _value;
_common.doUpdate();
ttsCommit;
Если я сразу его меняю на:
X++:
ttsBegin;
_common.selectForUpdate(true);
_common.reread();
_common.(_fieldId) = _value;
_common.doUpdate();
ttsCommit;
Код так же продолжает корректно работать.
Если я в коде убираю _common.reread(), т.е. хочу сгененрировать ошибку:
X++:
ttsBegin;
_common.selectForUpdate(true);
//_common.reread(); // <-- убираю
_common.(_fieldId) = _value;
_common.doUpdate();
ttsCommit;
Естественно возникает эта ошибка. И если я снова возвращаю:
X++:
ttsBegin;
_common.selectForUpdate(true);
_common.reread(); // <-- возвращаю
_common.(_fieldId) = _value;
_common.doUpdate();
ttsCommit;
ошибка не пропадает а остается.
Помогает снова обойти эту ошибку изменение кода на:
X++:
ttsBegin;
select forupdate _common
	where _common.recid == _common.recid;
_common.(_fieldId) = _value;
_common.doUpdate();
ttsCommit;
Добавлю что речь про AX09.

Последний раз редактировалось oleggy; 03.09.2021 в 09:40.
Старый 03.09.2021, 10:01   #17  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Условие where _common.recid == _common.recid равносильно условию where true или что тоже самое отсутствию условия. Если у вас в таблице (APMParameters) одна запись то она и выберется и вы не почувствуете разницы. На таблицах с несколькими записями такой запрос вернёт вам первую попавшуюся запись, а не обязательно ту с которой вы работали.
Старый 03.09.2021, 12:04   #18  
oleggy is offline
oleggy
Участник
 
276 / 36 (2) +++
Регистрация: 03.12.2019
Адрес: Россия
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Условие where _common.recid == _common.recid равносильно условию where true или что тоже самое отсутствию условия. Если у вас в таблице (APMParameters) одна запись то она и выберется и вы не почувствуете разницы. На таблицах с несколькими записями такой запрос вернёт вам первую попавшуюся запись, а не обязательно ту с которой вы работали.
Странно, но
X++:
select table where true;
не меняет запись.
А этот меняет.
X++:
select table where table.recId == table.recId;
Вот сами проверьте:
X++:
Address address;
RecId recId = 5637314047;
;

select address where address.recId == recId;
	
select address where address.recId == address.recId; // тут меняется recId

//select address where true; // тут не меняется recId

if (recId != address.RecId)
info('меняется');
Старый 03.09.2021, 14:13   #19  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от oleggy Посмотреть сообщение
Странно, но ...
Ничего странного. Вообще оба запроса могут вернуть абсолютно любую запись случайным образом. Сегодня могут вернуть то, что было в первом запросе, завтра что-нибудь другое.
Оба запроса почти равнозначны. Просто в = true, скорее всего, вообще проигнорируется условие движком MS SQL (или Аксапты), второй что-нибудь попробует сравнить (а может и нет), но все равно для каждой записи таблицы условие выполняется.
В базе в таблице хранится "неупорядоченный кортеж", если прямо не сортировать в самом запросе, то порядок выборки неопределен.
Конечно, могут влиять кластерные индексы, кэшированные данные, фаза луны, расположение звезд. Но закладываться на то, что это постоянное влияние, не следует.
В итоге, обсуждение чисто теоретическое и пользы, немного, какие бы предположения не делались.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
DAX2009 странный баг, в любой форме отображается только 1-я запись oleggy DAX: Администрирование 4 24.06.2021 21:30
Невозможно выбрать запись, ...База данных SQL обнаружила ошибку actNaturally DAX: Администрирование 4 11.12.2014 12:56
axforum blogs: Ошибка обновления Организации при установке UpdateRollup Blog bot DAX Blogs 0 11.04.2013 20:11
Не корректно сохраняет запись в inventTable Starling DAX: Программирование 8 31.03.2008 15:30
Ошибка при импорте демоданных (Axapta 3.0 CIS SP1) KocDm DAX: Администрирование 2 11.08.2005 12:04

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

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 12:08.