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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 17.07.2011, 22:59   #1  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Post Программное воссоздание записей SqlDictionary для определенной таблицы
В пору обновления приложения Axapta 3.0 до AX 2009 я столкнулся с серьезной проблемой при подъеме модификаций для таблиц, поля которых в стандарте используют идентификаторы из диапазона usr-слоя (см. тему DAX2009: поля таблиц стандартного приложения с идентификаторами из диапазона usr-слоя). Попытки синхронизации таких таблиц неизменно заканчивались ошибками, а поскольку происходило все на пустой разрабоческой базе, было решено обойти придурь ядра с помощью "программной эмуляции": удалить вообще записи в SqlDictionary для проблемных таблиц и воссоздать их, "как положено". Ниже приводится использовавшийся для этого код, немного сдобренный комментариями, - авось еще кому пригодится. В коде поля типа UtcDateTime обрабатываются специальным образом, обсуждение см. в теме Зачем нужно поле для хранения временной зоны для значений полей типа UtcDateTime?
X++:
public static server void sqlDictionaryFill4Table(tableId _tableId)
{
    #macrolib.DictField
    #define.RecIdBaseType   (49)                // для полей с типом RecId/RefRecId/createdTransactionId/modifiedTransactionId используется не Types::Int64, а этот тип
    #define.TZIDsuffix      ('_TZID')           // для несистемных полей типа UtcDateTime в БД создается дополнительное поле с кодом временной зоны, в которой было записано значение

    SqlDictionary   sqlDict;
    SysdictType     dictType;
    DictTable       dictTable = new DictTable( _tableId );
    DictField       dictField;
    ArrayIdx        arrIdx;
    Counter         numOfSqlFields;             // сколько записей для полей таблицы должно быть в SqlDictionary
    fieldName       fieldName;
    fieldId         fieldId;

    boolean processTableField(DictField _dictField, ArrayIdx _arrIdx, boolean _isTzIdField = false)
    {
        ArrayIdx    dictArrIdx;
        str         infoName;                   // это имя поля сугубо для сообщений
        FieldName   sqlName;
        boolean     ret;
        ;
        if (_isTzIdField)
        {
            if (    _dictField.baseType()   != Types::UtcDateTime
                ||  _dictField.id()         == fieldnum(Common, createdDateTime)
                ||  _dictField.id()         == fieldnum(Common, modifiedDateTime)
               )
            {
                throw error( Error::wrongUseOfFunction( funcname() ) );
            }
            dictArrIdx  = _dictField.arraySize() + _arrIdx;
            sqlName     = _dictField.dateTimeTimeZoneRuleFieldName( _arrIdx - 1 );
            infoName    = _dictField.name() + #TZIDsuffix;
        }
        else
        {
            dictArrIdx  = _arrIdx;
            sqlName     = _dictField.name( DbBackend::Sql, _arrIdx );
            infoName    = _dictField.name();
        }
        select firstonly sqlDict
            where   sqlDict.tabId   == _dictField.tableid()
                &&  sqlDict.fieldId == _dictField.id()
                &&  sqlDict.array   == dictArrIdx
                    ;
        if (!sqlDict)
        {
            sqlDict.clear();
            sqlDict.initValue();
            sqlDict.tabId           = _dictField.tableid();
            sqlDict.fieldId         = _dictField.id();
            sqlDict.array           = dictArrIdx;
            sqlDict.name            = strupr( _dictField.name( DbBackend::Native, _arrIdx ) );
            sqlDict.sqlName         = sqlName;
            dictType                = new SysDictType( _dictField.typeId() );
            if (_isTzIdField)
            {
                sqlDict.fieldType   = Types::Integer;
            }
            else
            if (        _dictField.id()     == fieldnum(Common, RecId)
                ||      _dictField.id()     == fieldnum(Common, createdTransactionId)
                ||      _dictField.id()     == fieldnum(Common, modifiedTransactionId)
                ||      _dictField.typeId() == typeid(RecId)
                ||      _dictField.typeId() == typeid(RefRecId)
                ||  (   dictType
                    &&  dictType.isExtending( extendedtypenum(RecId) )
                    )
               )
            {
                // для RecId в поле fieldType прописывается не Types::Int64, а число 49
                sqlDict.fieldType   = #RecIdBaseType;
            }
            else
            {
                sqlDict.fieldType   = _dictField.baseType();
            }
            sqlDict.strSize         = _dictField.stringLen();
            sqlDict.shadow          = bitTest( _dictField.flags(), #DBF_SHADOW );
            sqlDict.rightJustify    = bitTest( _dictField.flags(), #DBF_RIGHT );
            sqlDict.nullable        = _dictField.baseType() == Types::Container || _dictField.baseType() == Types::VarString;
            sqlDict.flags           = sqlDict.shadow;   // а вот ни фига не _dictField.flags();
            if (sqlDict.validateWrite())
            {
                sqlDict.insert();
                ret = true;
                info( strfmt( @"Создана запись для поля %1.%2%3",
                                dictTable.name(), infoName, _dictField.arraySize() > 1 ? strfmt( @"[%1]", _arrIdx ) : ''
                    ));
                // для всех несистемных полей UtcDateTime создаем также связанное поле TZID
                if (   !_isTzIdField
                    &&  _dictField.baseType()   == Types::UtcDateTime
                    &&  _dictField.id()         != fieldnum(Common, createdDateTime)
                    &&  _dictField.id()         != fieldnum(Common, modifiedDateTime)
                   )
                {
                    processTableField( _dictField, _arrIdx, true );
                }
            }
            else
            {
                ret = checkFailed( strfmt( @"Запись в %1 для поля %2.%3 не была создана", tablestr(SqlDictionary), dictTable.name(), infoName ) );
            }
        }
        return ret;
    }
    ;
    if (!dictTable)
    {
        throw error( strfmt( @"Не удалось создать объект %1 для таблицы '%2' (%3)", classstr(DictTable), tableid2name( _tableId ), _tableId ) );
    }
    if (dictTable.isSystemTable())
    {
        throw error( strfmt( @"Таблица '%1' - системная, на это я пойтить не могу", dictTable.name() ) );
    }
    if (!dictTable.isSql())
    {
        throw error( strfmt( @"Таблицы '%1' вообще не должно быть в базе", dictTable.name() ) );
    }
    for (fieldId = dictTable.fieldNext( 0 ); fieldId; fieldId = dictTable.fieldNext( fieldId ))
    {
        dictField = dictTable.fieldObject( fieldId );
        if (dictField && (dictField.flags() & #DBF_STORE))
        {
            fieldName = dictField.name();
            for (arrIdx = 1; arrIdx <= dictField.arraySize(); arrIdx++)
            {
                numOfSqlFields++;
                processTableField( dictField, arrIdx );
            }
        }
    }
    select firstonly sqlDict
        where   sqlDict.tabId   == _tableId
            &&  sqlDict.fieldId == 0
                ;
    if (!sqlDict)
    {
        sqlDict.clear();
        sqlDict.initValue();
        sqlDict.tabId       = _tableId;
        sqlDict.name        = strupr( dictTable.name() );
        sqlDict.sqlName     = dictTable.name( DbBackend::Sql );
        sqlDict.strSize     = numOfSqlFields;       // для "заголовка" таблицы тут указывается, сколько у нее полей в БД
        sqlDict.flags       = dictTable.isView();   // "мой дедуктивный метод..."
        sqlDict.insert();
        info( strfmt( @"Создана запись для таблицы %1", dictTable.name() ) );
    }
}
За это сообщение автора поблагодарили: raz (15), sukhanchik (10), propeller (1).
Теги
ax2009, sqldictionary, законченный пример

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Set записей таблицы OOuph DAX: Программирование 6 11.02.2008 10:27
Как добавить в фильтрацию записей доп. таблицы n:1 или 1:n? Hidden DAX: Программирование 6 11.08.2006 14:04
вывод количества записей в таблице на web форме и указание текущей страницы таблицы bambuk1960 DAX: Программирование 1 06.07.2006 13:27
Программное создание новых записей Владимир Максимов DAX: Программирование 35 06.03.2006 14:08
Lookupы при большом количестве записей выводимой таблицы Pavlo AKA Panok DAX: Программирование 9 07.05.2002 22:02
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

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