16.03.2009, 17:34 | #1 |
Участник
|
Смена первичного ключа таблицы 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 |
MCTS
|
Почему обновляете VendTable, а не findVendTable?
|
|
16.03.2009, 18:34 | #3 |
Участник
|
и метод renamePrimaryKey есть на самой таблице.
лучше вызывать сразу findVendTable.renamePrimaryKey(); не заморачиваясь на CC*-классы. кроме того, не вызывайте renamePrimaryKey если код не изменился. Это очень тяжелый метод. |
|
16.03.2009, 19:06 | #4 |
Участник
|
Насколько я понял из скудного описания - метод CCRenamePrimaryKey - производит поиск обновляет ссылки во всех связанных проводках, если я не буду его использовать, сохраню ли целостность данных?
|
|
16.03.2009, 19:13 | #5 |
Участник
|
Цитата:
семейство классов CC* - обертка над работой с таблицами из интерфейса пользователя. Если вы пишете код, то использовать CC* - избыточно. Работайте с методами таблицы напрямую. |
|
16.03.2009, 19:21 | #6 |
Участник
|
Цитата:
он как раз не занимается связанными таблицами. он обновляет только одну указанную таблицу. юзайте специальный метод на таблице. |
|
16.03.2009, 19:29 | #7 |
Участник
|
Ок, я понял. Так будет правильно?
X++: strToUpdate = strpoke(vendtable.AccountNum, "С", strfind(vendtable.AccountNum,"C", 1, strlen(vendtable.AccountNum))); findVendTable.renamePrimaryKey() VendTable.AccountNum = strToUpdate ; findVendTable.renamePrimaryKey(); findVendTable.update(); |
|
16.03.2009, 19:45 | #8 |
Участник
|
Цитата:
Сообщение от Masterofmind
Ок, я понял. Так будет правильно?
X++: strToUpdate = strpoke(vendtable.AccountNum, "С", strfind(vendtable.AccountNum,"C", 1, strlen(vendtable.AccountNum))); findVendTable.renamePrimaryKey() VendTable.AccountNum = strToUpdate ; findVendTable.renamePrimaryKey(); findVendTable.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; } } |
|
|
За это сообщение автора поблагодарили: Masterofmind (1). |
16.03.2009, 19:54 | #9 |
Участник
|
Commit я использую для того, чтобы в случае глобальной ошибки не откатывалась все транкзакция( мое предположение, что будет откачена вся транкзакция). Опыта маловата и недостаток знаний приходится компенсировать воображением и предполагать... такой подход пусть и длительней - зато дает гарантию - что проапдейтились все записи, до возникновения исключающей ошибки. Для меня важен результат, а это - правильно пропатчинные справочник и проводки.
|
|
16.03.2009, 19:56 | #10 |
Участник
|
Кстати, заметил еще одну багу в вашем коде.
Цитата:
поэтому использовать потом AccountNum бесполезно - там всегда будет пустое значение. |
|
16.03.2009, 19:57 | #11 |
Участник
|
Цитата:
Сообщение от Masterofmind
Commit я использую для того, чтобы в случае глобальной ошибки не откатывалась все транкзакция( мое предположение, что будет откачена вся транкзакция). Опыта маловата и недостаток знаний приходится компенсировать воображением и предполагать... такой подход пусть и длительней - зато дает гарантию - что проапдейтились все записи, до возникновения исключающей ошибки. Для меня важен результат, а это - правильно пропатчинные справочник и проводки.
но в этом джобе вы можете получить промежуточное состояние - часть записей уже обновлена, а часть - не обновлена. Если это не ошибка, то все нормально. |
|
16.03.2009, 23:22 | #12 |
Участник
|
И еще не забудьте, что есть еще такие вещи, как LedgerJournalTrans с ее AccountNum/OffsetAccount, которые могут содержать коды еще и из другой компании, и после штатного "переименования во всех связанных таблицах" строки журналов ГК с соотв.кодами поставщиков у вас могут "отвалиться" от VendTable. На CustTable вроде пытались это лечить, но, как всегда, криво, в частности, без учета того, что CustTable та же может быть в виртуальной компании; где-то вроде об этом уже писали... В общем, не все так просто
|
|