AXForum  
Вернуться   AXForum > Блоги > Трудности перехода
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

Заметки об опыте перехода с Axapta 3.0 на AX 2009
Оценить эту запись

Трудности перехода: опыт переноса модификаций с AX 3.0 SP5 EE на AX 2009 SP1 RU5 EE

Запись от gl00mie размещена 19.07.2011 в 03:10

Это краткие заметки ("зарубки" ), которые я делал по ходу обновления приложения. Сразу хочу предупредить, что все, описанное ниже, относится к способу подъема модификаций из старого приложения на новое слоем и последующего их "доведения до ума". При подъеме модификаций проектами ситуация может существенно отличаться. Однако, мне известен как минимум один косяк экспорта в 3.0, из-за чего перенос модификаций проектами может исказить результаты, плюс к этому стандартные инструменты обновления приложения также не рассчитаны на такой сценарий.

Подготовка к переходу

Начинайте подготовку к переходу как можно раньше, возможно, за несколько месяцев до активной фазы с обновлением приложения и конвертацией данных.
Если объем ваших модификаций невелик, можно особо не беспокоиться, однако если их много, то стоит по возможности переработать код приложения еще на версии 3.0. Дело в том, что по сравнению с 3-ей версией код приложения в AX 2009 очень сильно изменился. Зачастую модификации в тех или иных стандартных методах приходится поднимать на 2009-ю так: копировать куда-нибудь код измененного в 3-ке метода, удалять его с usr-слоя, возвращаясь к новому стандартному коду, а затем заново вручную накатывать сделанные ранее модификации - добавлять строки своего кода, новые параметры методов и т.п. Поэтому какие-то слишком большие куски своего кода имеет смысл выносить в отдельные методы и дергать их в модифицируемом стандартном коде, а не дописывать своей логики на 2-3 экрана (впрочем, так имеет смысл делать всегда, безотносительно перспектив перехода). Также целесообразно оценить примерное время, которое понадобится на обновление приложения, с помощью штатных средств: построить проект с выявленными конфликтами при обновлении приложения и запустить штатный отчет, который на основании этого проекта оценивает необходимое для их устранения время. Не стоит ориентироваться на опыт перехода, к примеру, на другой Service Pack для 3-ей версии, поскольку, опять же, стандартные приложения для версий 3.0 и 2009 очень сильно отличаются. Если планируется сразу по ходу обновления приложения начать использовать новые стандартные возможности в дополнение или вместо своих модификаций, на это следует заложить дополнительное время.

Соберите статистику по тем объектам приложения, которые реально используются (формы, отчеты, а также наследники RunBase)
В 2009-й есть собственная штатная инфраструктура по сбору статистики использования объектов приложения, но она работает лишь для форм и отчетов и не дает представления о том, насколько часто используются те или иные объекты приложения (см. также эту тему. Возможно, у вас есть какие-то уже не используемые классы (в данном случае интересны лишь наследники RunBase - для них проще всего реализовать сбор статистики), формы, отчеты - не стоит тратить время и силы на перенос их кода, если они реально не нужны. В любом случае, старое приложение, думаю, долгое время останется в пределах досягаемости, так что какие-то доработки можно будет перенести из него отдельно. Статистику по использованию объектов приложения следует собирать в течение как минимум 3-х месяцев. Для наследников RunBase код сбора статистики имеет смысл вызывать в new(), для форм - в classFactory; чтобы избежать возможных блокировок на обновлении статистики, можно воспользоваться подходом, использовавшимся в LedgerBalances*Trans: на каждый объект приложения сохранять не одну, а несколько записей, выбирая их случайным образом.

Подготовка к обновлению приложения

Изучите документацию по обновлению приложения
В руководстве по обновлению есть скупая, но важная информация по обновлению приложения. Например, кроме того, что в каталог OLD нужно скопировать все старое приложение, а к стандратному приложению - скопировать дополнительно все файлы приложения и меток для слоев выше dis, нужно в OLD-каталоге не забыть переименовать файлы dis-слоя в hfx, иначе 2009-я просто не увидит целый слой в старом приложении.

Соберите максимально полный и актуальный набор слоев для стандартного приложения, на которое будете переходить
В моем случае на момент начала перехода последним доступным обновлением был Rollup 4 (RU4) - RU5 появился, когда обонвление приложения было уже почти завершено, но было решено перейти на него, тем более что приложение еще не было протестировано. Кроме того, теперь отдельным слоем (sl2) идут локализованные модули "СНГ Кадровый учет" и "СНГ Зарплата", которые раньше были частью dis-слоя. Даже если у вас нет лицензий на эти модули, имеет смысл включить в состав стандартного приложения и этот слой, поскольку часть его функционала - то, что относится к конфигурационному ключу RPayHRMCommon - не закрыта лицензионными ключами, и весьма может быть, что вы так или иначе используете этот функционал. Только надо учесть, что слой sl2, поднятый на соответствующий Rollup, выходит позже самого Rollup'а; очень важно, чтобы он соответствовал Rollup'у, в противном случае слой sl2 может затереть кое-какие модификации, сделанные на слоях syp/glp: могут пропасть новые значения enum'ов, некоторые определения макросов в ClassDeclaration классов и т.п. Следствием всего этого может стать то, что код стандартного приложения будет компилироваться с ошибками либо просто не работать, как предполагается.

После формирования стандартного приложения соберите перекрестные ссылки
Вам, скорее всего, понадобится иметь два набора перекрестных ссылок: по стандартному функционалу приложения AX 2009 и по приложению версии 3.0, которое вы собираетесь обновлять. Получить полноценные перекрестные ссылки после того, как вы подложите свои слои (usr, возможно, cus и прочие выше dis-слоя) к стандартному приложению AX 2009, будет проблематично, поскольку приложение в ряде мест перестанет компилироваться. В связи с этим собрать перекрестные ссылки следует по приложению AX 2009 без слоев с кастомизациями.

Изучите новые и допилите старые инструменты для обновления приложения
В AX 2009 появился ряд новых замечательных инструментов для обновления, один из которых позволяет выявить конфликты при обновлении приложения. Суть его в том, что семейство классов анализирует три версии объекта приложения: старую (стандартное приложение 3.0 в данном случае), вашу (модифицированные объекты стандартного приложения) и "их" версию (стандартное приложение AX 2009 в данном случае) и на основе этого сравнения выявляет ряд конфликтов, а также, что очень ценно, может автоматически разрешать некоторые типы конфликтов, связанные с изменением свойств объектов. В AX 2009 по сравнению с 3.0 у таких объектов приложения, как таблицы, поля таблиц, дизайн и отдельные элементы управления форм и отчетов, появилось несколько новых свойств. Соответственно, у объектов стандартного приложения они могут быть заполнены, в то время как у объектов, поднятных из 3.0 на usr-слое, эти свойства будут иметь значения по умолчанию. Автоматическое "дозаполнение" таких свойств в соответствии с тем, каковы их значения в стандратном приложении, избавит вас от значительного объема рутинной работы.
Стоит опробовать в деле новый инструмент сравнения объектов: он был переработан, в частности, выбор слоёв по умолчанию в качестве исходного и конечного может оказаться непривычным, хотя в этом есть своя логика. Стоит "пообвыкнуться" с новым инструментом и, возможно, заранее модифицировать его работу под себя: возможно, включить сохранение размеров окна, приделать автозапуск сравнения при некоторых условиях и т.п. Также неоценимую услугу окажут перекрестные ссылки, собранные для старого приложения. Я немного модифицировал собираемые данные, чтобы можно было видеть не только где используется тот или иной объект, но и на каком слое находится код или объект приложения, его использующий. В этом случае можно легко отфильтровать данные, чтобы видеть только кастомизированный код либо, наоборот, только стандартный.

код по модификации перекрестных ссылок для отображения прикладного слоя

Приведенный код может показаться излишне усложненным, но это было вызвано "особенностями" работы ядра 3.0 с объектами TreeNode: как оказалось, если создавать достаточно много таких объектов (а в таблице xRefPaths, куда пишется код слоя, может создаваться порядка 700 тысяч записей), Аксапта может "свалиться" и не довести сбор перекрестных ссылок до конца.
Также стоит учесть, что штатный механизм построения проекта выявления конфликтов при обновлении кода не рассчитан на масштабно модифицированные приложения - по всему AOT'у проект может так и не собраться (опять-таки, клиент просто свалится, вероятно, тоже из-за интенсивного использования TreeNode). Для решения этой проблемы код соответствующего класса был немного модифицирован с тем, чтобы научиться собирать такой проект по указанной подветке AOT.

код по модификации сбора проекта выявления конфликтов при обновлении кода

Кроме этого, весьма вероятно, придется возиться с SqlDictionary - может понадобиться инструмент для заполнения этой таблицы по данным приложения, если в ходе обновления они как-то особо сильно разъедутся, и ядро откажется проводить синхронизацию базы (встречались случаи, когда не помогала ни синхронизация таблицы, ни проверка/синхронизация из формы администрирования SQL). К примеру, если у вас пересеклись идентификаторы полей на sys и usr-слоях, то никакие штатные синхронизации не помогут. В таких случаях приходилось, порой, просто удалять записи в SqlDictionary для проблемных полей и пересоздавать их заново.

код дозаполнения таблицы SqlDictionary для выбранной таблицы

Настройте резервное копирование
Возможно, этот момент покажется многим очевидным, и тем не менее: обновление приложения может занять не один человеко-месяц работы, и было бы очень обидно потерять наработанные результаты, поэтому имеет смысл настроить резервное копирование пусть не всего приложения, а хотя бы обновляемого вами слоя. Также стоит создавать резервные копии базы, используемой при обновлении приложения, ведь в ней содержится ценная информация по ходу обновления (данные для проектов выявления конфликтов при обновлении кода и проч.)

Спланируйте последовательность обновления
Последовательность обновления отдельных типов и групп объектов приложения может оказать очень существенное влияние на сроки выполнения проекта и возможности по распараллеливанию работ. Если проект выполняется силами более чем одного человека, успешное распараллеливание работ (например, по обновлению объектов приложения и их тестированию) является одним из важнейших условий для соблюдении приемлемых сроков обновления. В целом, особенно если модификаций много, очень может пригодиться инкрементный подход к обновлению приложения: выделив наиболее важные ежедневные операции, можно начать обновлять последовательно те формы, отчеты, классы и т.д., которые в них используются. Это позволит за относительно короткие итерации получать блоки работающего обновленного функционала, который можно передать на тестирование и за счет этого распараллелить процесс обновления и тестирования приложения. При этом можно будет сконцентрироваться на наиболее важном для компании функционале, обновляя его в первую очередь и оставив обновление менее приоритетного функционала на потом. Напротив, обновление "методом большого взрыва", как и в разработке, скорее всего приведет к срыву всех мыслимых сроков проекта. В первую очередь следует обновить словарь данных (Data Dictionary) - сразу после этого можно будет начать тестовую конвертации базы, которая может занять ощутимое время. Сконвертированная (пусть пока и с ошибками) база вскоре понадобится для тестирования обновленного функционала, поэтому ее нужно получить как можно раньше.

Собственно обновление приложения

Обновите словарь данных в первую очередь
Хоть это и очевидно, но не помешает повторить. Стоит придерживаться определенной последовательности при обновлении приложения: сперва... впрочем, даже не Data Dictionary, а наиболее важные при обновлении системные классы (Application, Info, ClassFactory, Global, SysSetupFormRun, SysQuery) и формы, затем Data Dictionary, а затем уже остальные формы, отчеты, классы и проч. Если не очень повезет, то первые несколько часов обновления могут уйти на то, чтобы клиент просто запустился без ошибок.

Обратите внимание на измененные таблицы, расширенные типы - возможно, в стандартном приложении у них поменялся конфигурационный ключ, а вы со своими модификациями подняли на новое приложение определения этих объектов с конфигурационными ключами из предыдущей версии приложения. Это чревато очень серьезными неприятностями! К примеру, тот ключ, который вы "подняли" вместе с модификацией свойств таблицы, может в новом приложении стать дочерним к ключу SysDeletedObjects41 (яркий пример - ключ CRSECIS). В этом случае вы можете успешно обновить приложение, сконвертировать базу, но когда вы отключите ключи SysDeletedObjects40 и SysDeletedObjects41, часть ваших данных может пропасть! При этом штатный инструмент разрешения конфликтов свойств в таких ситуациях НЕ изменяет конфигурационный ключ, считая это свойство объектов доступным лишь для чтения. Чтобы продиагностировать и при необходимости исправить ситуацию, можно воспользоваться кодом по приведенной ниже ссылке. Следует также внимательно просмотреть, какие конфигурационные ключи сделаны дочерними к SysDeletedObjects41 - возможно, вы используете какой-то функционал, который привязан к этим ключам. Стоит внимательно проверить по перекрестным ссылкам, какие таблицы, поля или расширенные типы привязаны к этим ключам, используются ли они в ваших модификациях.

код диагностики и исправления "съехавших" конфигурационных ключей на таблицах

Посмотрите, не изменились ли идентификаторы модифицированных вами стандартных классов
Если вам "повезло", и идентификатор модифицированного вами класса стандартного приложения изменился в новой версии, то ядро может "забыть" про ваши модификации, хотя они будут все также находиться на соответствующем слое (предположительно usr), класс же будет в AOT выглядеть так, будто он не модифицирован вовсе. На сравнении таких классов будут выдаваться предупреждения, что идентификаторы отличаются на разных слоях. К примеру, при прогоне тестового джоба на приложениях AX 3.0 SP5 FP1 EE (в OLD) и AX 2009 SP1 RU4 EE + слой sl2 с модулями "СНГ Зарплата" и "СНГ Кадровый учет" было найдено 66 таких классов, из них лишь 4 на sys-слое, остальные - на gls/sl2.
X++:
// выявляет отличия в идентификаторах классов стандартного приложения, сравнивая текущее приложение и приложение в OLD-каталоге
UtilIdElements      ue;
UtilIdElementsOld   ueOld;
identifiername      name;
SetEnumerator       setEnum;
MapEnumerator       mapEnum;
Map                 mapOldName2Id   = new Map( typeof(ue.name), typeof(ue.Id) );
Map                 mapNewName2Id   = new Map( typeof(ue.name), typeof(ue.Id) );
Set                 setOfCommonNames;
classid             newId;
classid             oldId;
Counter             n;
;
setprefix( @"Классы стандартного приложения, у которых изменился идентификатор" );
while select name, id, utilLevel
    from    ue
    where   ue.recordType       == UtilElementType::Class
        &&  ue.utilLevel        <  UtilEntryLevel::bus
{
    mapNewName2Id.insert( ue.name, ue.Id );
}
while select name, id, utilLevel
    from    ueOld
    where   ueOld.recordType    == UtilElementType::Class
        &&  ueOld.utilLevel     <  UtilEntryLevel::bus
{
    mapOldName2Id.insert( ueOld.name, ueOld.Id );
}
setOfCommonNames = Set::intersection( mapNewName2Id.keySet(), mapOldName2Id.keySet() );
setEnum = setOfCommonNames.getEnumerator();
while (setEnum.moveNext())
{
    name    = setEnum.current();
    oldId   = mapOldName2Id.lookup( name );
    newId   = mapNewName2Id.lookup( name );
    if (newId != oldId)
    {
        select firstonly name, id, utilLevel
            from    ue
            order by utilLevel desc
            where   ue.name             == name
                &&  ue.recordType       == UtilElementType::Class
                &&  ue.utilLevel        <  UtilEntryLevel::bus
                    ;
        select firstonly name, id, utilLevel
            from    ueOld
            order by utilLevel desc
            where   ueOld.name          == name
                &&  ueOld.recordType    == UtilElementType::Class
                &&  ueOld.utilLevel     <  UtilEntryLevel::bus
                    ;
        info( strfmt( @"%1 old %2 id %3, new %4 id %5", name, ueOld.utilLevel, ueOld.Id, ue.utilLevel, ue.Id ));
        n++;
    }
}
info( strfmt( @"Найдено %1 объектов", n ) );

Посмотрите, не пересеклись ли идентификаторы табличных полей в стандартном приложении и созданные вами
Это касается как собственно полей таблиц (например, в CustParameters у 3-х полей с sys-слоя идентификаторы - из диапазона, отведенного usr-слою), так и полей Map. С Map'ами нужно быть очень осторожным, потому что их "кривизна" может приводить к очень труднодиагностируемым ошибкам: отладчик по-прежнему "не понимает" Map'ы и соотв. переменные показывает как табличные переменные той или иной реальной таблицы, позволяя посмотреть те же поля лишь по названиям в таблице, а не в Map'е.

код поиска объектов стандартного приложения с идентификаторами из диапазона usr-слоя

Обратите внимание на стандартные методы, у которых изменилось число параметров
Очень внимательно обновляйте те методы в модифицированном вами коде, где в стандартном приложении добавились новые параметры со значениями по умолчанию. Если их типы совпадают с типами добавленных вами параметров (обычно boolean), то некорректно обновленный код может начать вызывать эти методы, передавая значения не тех параметров, которые изначально задумывались автором модификации. Это касается, к примеру, таких методов, как SalesLineType.insert(), SalesLineType.update() и т.п.

После обновления приложения стоит заняться вопросами конвертации базы, но это - отдельная история...
Размещено в Без категории
Просмотров 64902 Комментарии 0
Всего комментариев 0

Комментарии

 


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