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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 16.03.2009, 17:34   #1  
Masterofmind is offline
Masterofmind
Участник
Аватар для Masterofmind
 
5 / 10 (1) +
Регистрация: 28.05.2008
? Смена первичного ключа таблицы VendTable
Доброго дня, коллеги.

Сразу извиняюсь за возможный оффтоп, но очень срочно нужен совет гуру. При импорте первичных данных в систему (DAX 4.0 SP2 - 3-х звенка) был допущен один промах, а именно - в кодах поставщиков присутствуют и латинская и русская буква С. Задача - перекодировать все первичные ключи и заменить (где присутствует) латинскую С на русскую С.
Формат кода - XXСПYYYYYYY, где XX-код подразделения за которым числится поставщик, а YYYYYYY - порядковый номер формата 0000021

Я имею очень скромный опыт программирования в DAX, вот попытался написать, который все это дело исправляет:
X++:
static void Base1000_RenameVendPrKey(Args _args)
{
    vendTable        vendTable,
                     findVendTable;

    str              strToUpdate;
    ;

    while select recid from vendTable
        where vendTable.AccountNum like "*C*"
    {
        try
        {
            ttsbegin;

            findVendTable = VendTable::findRecId(vendTable.RecId, true);

            if(findVendTable)
            {
                strToUpdate = strpoke(vendtable.AccountNum, "С", strfind(vendtable.AccountNum,"C", 1, strlen(vendtable.AccountNum)));

                CCPrimaryKey::renamePrimaryKey(VendTable, strToUpdate, fieldNum(VendTable, AccountNum)); // переименование во всех связанных таблицах

                VendTable.AccountNum = strToUpdate ;

                VendTable.renamePrimaryKey(); // переименование в основной таблице

                //VendTable.update();
            }

            ttscommit;
        }
        Catch (exception::error)
        {
             exceptionTextFallThrough(); // вывод ошибки

             ttsabort;
             retry; // повтор блока try
        }
    }
}
Джоб почему-то не работает, или вылетает с ошибкой, которую я перехватить не могу. Ошибка я так понимаю идет из-за блокировки таблицы.
По идее я хочу перехватывать ошибку блокировки и пытаться апдейтить следующую запись, и таким образом - путем нескольких итераций привести справочник к "употребляемому" руководством виду.

Ваше мнение господа? Помогите провести аудит кода и подскажите, ЧТО именно я не так делаю.
Старый 16.03.2009, 18:25   #2  
twilight is offline
twilight
MCTS
MCBMSS
 
874 / 237 (9) ++++++
Регистрация: 17.10.2004
Адрес: Королёв
Почему обновляете VendTable, а не findVendTable?
Старый 16.03.2009, 18:34   #3  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
и метод renamePrimaryKey есть на самой таблице.
лучше вызывать сразу
findVendTable.renamePrimaryKey();
не заморачиваясь на CC*-классы.

кроме того, не вызывайте renamePrimaryKey если код не изменился. Это очень тяжелый метод.
__________________
полезное на axForum, github, vk, coub.
Старый 16.03.2009, 19:06   #4  
Masterofmind is offline
Masterofmind
Участник
Аватар для Masterofmind
 
5 / 10 (1) +
Регистрация: 28.05.2008
Насколько я понял из скудного описания - метод CCRenamePrimaryKey - производит поиск обновляет ссылки во всех связанных проводках, если я не буду его использовать, сохраню ли целостность данных?
Старый 16.03.2009, 19:13   #5  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Masterofmind Посмотреть сообщение
метод CCRenamePrimaryKey - производит поиск обновляет ссылки во всех связанных проводках
этим занимается метод renamePrimaryKey на самой таблице.

семейство классов CC* - обертка над работой с таблицами из интерфейса пользователя. Если вы пишете код, то использовать CC* - избыточно. Работайте с методами таблицы напрямую.
__________________
полезное на axForum, github, vk, coub.
Старый 16.03.2009, 19:21   #6  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Masterofmind Посмотреть сообщение
CCRenamePrimaryKey - производит поиск обновляет ссылки во всех связанных проводках
Кстати, посмотрел CCPrimaryKey::renamePrimaryKey
он как раз не занимается связанными таблицами.
он обновляет только одну указанную таблицу.

юзайте специальный метод на таблице.
__________________
полезное на axForum, github, vk, coub.
Старый 16.03.2009, 19:29   #7  
Masterofmind is offline
Masterofmind
Участник
Аватар для Masterofmind
 
5 / 10 (1) +
Регистрация: 28.05.2008
Ок, я понял. Так будет правильно?
X++:
strToUpdate = strpoke(vendtable.AccountNum, "С", strfind(vendtable.AccountNum,"C", 1, strlen(vendtable.AccountNum)));
        
                findVendTable.renamePrimaryKey()
                VendTable.AccountNum = strToUpdate ;
                findVendTable.renamePrimaryKey();
               
                findVendTable.update();
Строго не судите, это мой первый джоб, да и программированием я не занимался уже лет 5
Старый 16.03.2009, 19:45   #8  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Masterofmind Посмотреть сообщение
Ок, я понял. Так будет правильно?
X++:
strToUpdate = strpoke(vendtable.AccountNum, "С", strfind(vendtable.AccountNum,"C", 1, strlen(vendtable.AccountNum)));
        
                findVendTable.renamePrimaryKey()
                VendTable.AccountNum = strToUpdate ;
                findVendTable.renamePrimaryKey();
               
                findVendTable.update();
Строго не судите, это мой первый джоб, да и программированием я не занимался уже лет 5
не renamePrimaryKey используется вместо update.

правильно так (в аксапте не проверял)

X++:
static void Base1000_RenameVendPrKey(Args _args)
{
    vendTable        vendTable,
                     findVendTable;

    str              strToUpdate;
    ;

    while select recid from vendTable
        where vendTable.AccountNum like "*C*" // тут будет TableScan, ну и черт с ним: все равно надо обработать все записи
    {
        ttsbegin;

        findVendTable = VendTable::findRecId(vendTable.RecId, true);
        if(!findVendTable) continue;

        strToUpdate = strReplace(findVendTable.AccountNum, "С", "C"); // это из класса Global
        if( strToUpdate == findVendTable.AccountNum ) continue;

        findVendTable.AccountNum = strToUpdate;
        findVendTable.renamePrimaryKey(); // переименование во всех связанных таблицах

        ttscommit;
    }
}
ну, и конечно, стоит двадцать раз подумать прежде чем комиттить каждую запись.
в принципе транзакции получаются маленькими и но зафиксироваться может промежуточное состояние, когда обновлены не все записи. Если устраивает, то все нормально.

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

ну и наконец, чтобы работала комбинация Ctrl+Break стоит добавить ProgressBar

X++:
static void Base1000_RenameVendPrKey(Args _args)
{
    vendTable        vendTable,
                     findVendTable;

    str              strToUpdate;
    SysOperationProgress progress;
    ;

    select count(recid) from vendTable;
    progress = SysOperationProgress::newGeneral('','',vendTable.recid); // тут будет больше, чем будет обсчитано.
    // Ну и ладно. Запускать два раза tableScan не будем.

    while select recid from vendTable
        where vendTable.AccountNum like "*C*" // тут будет TableScan, ну и черт с ним: все равно надо обработать все записи
    {
        progress.inccount();
        ttsbegin;

        findVendTable = VendTable::findRecId(vendTable.RecId, true);
        if(!findVendTable) continue;

        strToUpdate = strReplace(findVendTable.AccountNum, "С", "C"); // это из класса Global
        if( strToUpdate == findVendTable.AccountNum ) continue;

        findVendTable.AccountNum = strToUpdate;
        findVendTable.renamePrimaryKey(); // переименование во всех связанных таблицах

        ttscommit;
    }
}
__________________
полезное на axForum, github, vk, coub.
За это сообщение автора поблагодарили: Masterofmind (1).
Старый 16.03.2009, 19:54   #9  
Masterofmind is offline
Masterofmind
Участник
Аватар для Masterofmind
 
5 / 10 (1) +
Регистрация: 28.05.2008
Commit я использую для того, чтобы в случае глобальной ошибки не откатывалась все транкзакция( мое предположение, что будет откачена вся транкзакция). Опыта маловата и недостаток знаний приходится компенсировать воображением и предполагать... такой подход пусть и длительней - зато дает гарантию - что проапдейтились все записи, до возникновения исключающей ошибки. Для меня важен результат, а это - правильно пропатчинные справочник и проводки.
Старый 16.03.2009, 19:56   #10  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Кстати, заметил еще одну багу в вашем коде.
Цитата:
Сообщение от Masterofmind Посмотреть сообщение
X++:
    ...select recid from vendTable...
    ...
    ...strToUpdate = strpoke(vendtable.AccountNum...
обратите внимание, что в селекте вы выбираете только recid.
поэтому использовать потом AccountNum бесполезно - там всегда будет пустое значение.
__________________
полезное на axForum, github, vk, coub.
Старый 16.03.2009, 19:57   #11  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Masterofmind Посмотреть сообщение
Commit я использую для того, чтобы в случае глобальной ошибки не откатывалась все транкзакция( мое предположение, что будет откачена вся транкзакция). Опыта маловата и недостаток знаний приходится компенсировать воображением и предполагать... такой подход пусть и длительней - зато дает гарантию - что проапдейтились все записи, до возникновения исключающей ошибки. Для меня важен результат, а это - правильно пропатчинные справочник и проводки.
ваше предположение правильно.
но в этом джобе вы можете получить промежуточное состояние - часть записей уже обновлена, а часть - не обновлена.
Если это не ошибка, то все нормально.
__________________
полезное на axForum, github, vk, coub.
Старый 16.03.2009, 23:22   #12  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от mazzy Посмотреть сообщение
правильно так (в аксапте не проверял)
X++:
static void Base1000_RenameVendPrKey(Args _args)
{
        // ...
        findVendTable.AccountNum = strToUpdate;
        findVendTable.renamePrimaryKey(); // переименование во всех связанных таблицах
}
И еще не забудьте, что есть еще такие вещи, как LedgerJournalTrans с ее AccountNum/OffsetAccount, которые могут содержать коды еще и из другой компании, и после штатного "переименования во всех связанных таблицах" строки журналов ГК с соотв.кодами поставщиков у вас могут "отвалиться" от VendTable. На CustTable вроде пытались это лечить, но, как всегда, криво, в частности, без учета того, что CustTable та же может быть в виртуальной компании; где-то вроде об этом уже писали... В общем, не все так просто
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Пересоздание таблицы при синхронизации Serg16 DAX: Администрирование 1 26.08.2009 13:55
Вставка строк в таблицы Аксапты сторонними средствами Андре DAX: База знаний и проекты 1 07.05.2009 16:49
Две таблицы в одном datasource Turetskiy DAX: Программирование 10 16.09.2008 16:35
Блокировка ключа индекса Sequel DAX: Программирование 4 06.07.2006 16:08
Получение из поля Map кода поля реальной таблицы, к ней привязанной (Mappings) vey DAX: Функционал 5 16.03.2005 11:16
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

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

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