С проведенной нормализацией модель данных в MicrosoftDynamics AX 2012 сильно изменилась. Большинство справочников приобрело сложную структуру, появились суррогатные ключи (по RecId). Все это сделало импорт данных гораздо более сложной задачей, в результате был разработан отдельный модуль Data Import/eXport Framework (DIXF или Data Migration Framework DMF). DMF создает промежуточную таблицу (staging table) для каждой сущности в базе данных Microsoft Dynamics AX. Staging table представляет собой необработанный промежуточный набор данных, плоское представление данных, полученных из исходного файла или базы данных. В качестве исходного объекта данных может быть сущность, представленная в виде нескольких таблиц (например, адреса). Промежуточная таблица нужна для проверки, очистки или преобразования передаваемых данных. Затем можно переместить данные в целевую таблицу или экспортировать их.
Процесс импорта экспорта.
Шаги, необходимые для импорта или экспорта данных в MicrosoftDynamics AX.
- Определение источника данных для экспорта или импорта и формата исходных данных. Для экспорта источником является AX. Для импорта можно использовать любой из следующих источников:
- AX — импорт данных из другого экземпляра Microsoft Dynamics AX.
- ODBC — импорт данных из другой базы данных, такой как Microsoft SQL Server или Microsoft Access.
- Файл — импорт данных из текстового файла с фиксированной шириной или с разделителями, файла XML или файла Microsoft Excel.
- Выбор объекта, который будет либо источником данных экспорта, либо целью данных импорта. Можно использовать существующий объект или создать собственный объект. Список доступных объектов расположен MainMenu/Структура импорта и экспорта данных/Настройка/Целевые объекты.
- Создание группы обработки для объектов, которые следует импортировать или экспортировать вместе. Группа обработки — это набор объектов, которые должны быть обработаны в нужной последовательности или которые могут быть логически сгруппированы вместе. Объекты в группе обработки экспортируются вместе или импортируются вместе из исходного в промежуточное состояние, а затем из промежуточного в целевое. В группе обработки вы также связываете каждый объект с исходным форматом данных.
- Непосредственно сам импорт или экспорт данных. Сам процесс осуществляется через функции доступные из группы обработки. Во время импорта сначала импортируются данные в промежуточную таблицу, где можно очистить или преобразовать данные по своему усмотрению. Затем идет перенос данных из промежуточной таблицы в целевую таблицу.
Важно! Microsoft настоятельно рекомендует удалить промежуточные данные после завершения миграции (MainMenu/Структура импорта и экспорта данных/Периодические операции/Очистка промежуточных данных).
Во время экспорта также перемещаются данные из источника в промежуточную таблицу. Затем эти данные экспортируются либо в Microsoft Dynamics AX, либо в файл. Первый вариант создает файлы .dat и .def, которые потом можно импортировать в другой экземпляр Microsoft Dynamics AX. Второй вариант создает файл с плоским представлением данных.
Создание пользовательских целевых объектов
Для каждой сущности AX используемой в DMF нужно: промежуточная таблица, проект, запрос, класс и функции. Можно использовать Мастер создания объекта, или создать их вручную. В обоих случаях потребуется существующая таблица в AOT.
Создание пользовательского объекта с помощью мастера
Мастер располагается «MainMenu /Структура импорта и экспорта данных/Обычный/Создать настраиваемый объект для импорта и экспорта данных»

- Выберите таблицу, связанную с объектом, который вы хотите перенести, и нажмите кнопку Далее. Внимание! Мастер может использоваться для создания пользовательских объектов, связанных только с таблицами, которые не наследуют структуры данных из других таблиц. Таблица должна существовать в AOT.

- На странице выбора параметров генерации кода выполните следующие действия:
- Мастер предлагает имена для промежуточной таблицы, запроса и класса. Можно принять эти имена или изменить их.
- Выберите пункт меню отображения для объекта.
- В зависимости от выбора Auto Generate Data добавляется либо метод генерации в класс, либо исходные таблицы для внешних ключей добавляются в запрос для сущности.
- Если объект будет использоваться с источником данных, который содержит связанные данные из двух таблиц, выберите «Является составным объектом». Поле RowID создается в промежуточной таблице. Это поле используется для сопоставления строк связанных данных друг с другом. Например, таблицы DMFSalesTableEntity и DMFSalesLineEntity, DMFPurchTableEntity и DMFPurchLineEntity, DMFBOMEntity и DMFBOMVersionEntity связываются по этому полю когда идет одновременный импорт шапки и строк. Эту связь можно увидеть в методе генерации естественного ключа \Classes\DMFBOMVersionEntityClass\GenerateBOMLink (entity = DMFBOMVersionEntity).
public Container GenerateBOMLink(boolean _stagingToTarget = true) { container res; BOMTable bomTable; HcmWorker worker; DirPartyTable partyTable; BOMConfigRoute bOMConfigRoute; boolean validate = true; if (_stagingToTarget) { if (this.isCompositeEntity() && entity.RowId) { res = [(select firstOnly1 DMFBOMEntity where DMFBOMEntity.RowId == entity.RowId && DMFBOMEntity.DefinitionGroup == entity.DefinitionGroup && DMFBOMEntity.ExecutionId == entity.ExecutionId).BOM_BOMId]; }
- По завершению мастера, DMF открывает вновь созданный проект для настраиваемого объекта в текущем слое.
- На странице «Поля на целевой таблице» выберите поля. Нажмите кнопку Далее.

- Если в выбранных таблицах используются расширенные типы данных (EDT), дважды выйдет диалоговое окно с вопросом, хотите ли вы добавить отношение ForeignKey из EDT в новую промежуточную таблицу. Каждый раз нажимайте Да, чтобы создать отношение ForeignKey. Также в макрос DMFEntityListName будет добавлена строка с названием основной таблицы источника данных (в данном примере #define.TutorialDMFTargetTable(‘TutorialDMFTargetTable’)
- Добавьте пользовательский объект в качестве нового целевого объекта на форму MainMenu/Структура импорта и экспорта данных/Настройка/Целевые объекты. В зависимости от объекта могут потребоваться некоторые дополнительные действия.
Ручное создание.
Создание промежуточной таблицы для объекта
- В AOT Microsoft Dynamics AX создайте промежуточную таблицу для объекта.
- Настройки свойств таблицы для промежуточной таблицы.
Property name Value SaveDataPerCompany No SupportInheritance No TableType Regular ConfigurationKey DMF ValidTimeStateFieldType None - Создайте стандартные поля
Field group name Label Field ExclusionList Exclusion List DefinitionGroup ** ** ** ** IsSelected ** ** ** ** TransferStatus ** ** ** ** ExecutionId Enabled Enabled Необязательно: Поля из промежуточной таблицы, которые вы хотите включить в шаблон по умолчанию. <<FunctionName_Sequence>>Example – GeneratePostalAddress_2 << Описание функции >>Функция, которая генерирует адрес Поля из промежуточной таблицы, которые являются источником для указанного метода. - При необходимости нужно создать первичный ключ. AllowDuplicates – No и AlternateKey – Yes, добавить поля DefinitionGroup и ExecutionId.
- Указать связь между промежуточной таблицей и целевой таблицей. Это отношение используется для автоматической связи конкретной промежуточной записи со связанной целевой сущностью. Если нельзя определить отношение с помощью узла отношения, нужно определить его с помощью метода addStagingLink () в классе сущности.
- Поля enum в целевом объекте представлены строковыми полями в промежуточной таблице. Нужно создать новый EDT строкового типа соответствующей длины для хранения строк меток значений перечисления. Преобразование между полем enum в целевом объекте и строковым полем в промежуточной таблице автоматически обрабатывается средой DMF.
Создание класса для объекта DMF.
DMFAttribute(true)]
class DMFTutorialDMFTargetTableEntityClass extends DMFEntityBase
{
DMFTutorialDMFTargetTableEntity entity;
TutorialDMFTargetTable target;
}
public void new(DMFTutorialDMFTargetTableEntity _entity)
{
entity = _entity;
}
public static DMFTutorialDMFTargetTableEntityClass construct(DMFTutorialDMFTargetTableEntity _entity)
{
DMFTutorialDMFTargetTableEntityClass entityClass = new DMFTutorialDMFTargetTableEntityClass(_entity);
return entityClass;
}
Метод setTargetBuffer.
Целевой объект может иметь несколько источников данных. Одним источником данных является основная таблица, которая представляет сущность. В методе setTargetBuffer параметр _dataSourceName представляет источники данных, которые присутствуют в запросе целевого объекта. В зависимости от количества источников данных в запросе может потребоваться дополнительная табличная переменная для связанного источника данных. Затем дополнительную переменную можно использовать в функциях, которые необходимы для переноса данных. Переменная target должна быть инициализирована главной таблицей, которая представляет целевой объект.
public void setTargetBuffer(Common _common, Name _dataSourceName = "")
{
switch (_common.TableId)
{
case tableNum(TutorialDMFTargetTable) :
target = _common;
break;
}
}
Метод jumpRefMethod
Имя пункта меню в мастере создания объекта нужно для создания метода jumpRefMethod
public container jumpRefMethod(Common _buffer,Object _caller)
{
MenuItemName menuItemName;
menuItemName = menuitemDisplayStr(TutorialDMFTargetTable);
entity = _buffer;
return [menuItemName,entity];
}
Свойство RunOn должно быть CalledFrom
Функции для импорта и экспорта данных
Можно сопоставить данные из промежуточного объекта в целевой объект двумя способами:
- Сопоставление поля в промежуточной таблице непосредственно полю в целевом объекте. В этом случае типы данных для промежуточных и целевых полей должны быть одинаковыми.
- Создать функцию X ++ для преобразования значений поля из промежуточной в целевую.
Функции (public container Generate…(boolean _stagingToTarget = true)) импорта и экспорта данных должны выполнять следующие действия:
- Input / Source – в этом случае переменная entity (промежуточная таблица) не пустая и параметр _stagingToTarget = true, соответственно можно использовать entity для вставки значений в целевую таблицу.
- Output/Target – это действие должно вернуть значения из целевой таблицы в виде контейнера.
Название метода функции должно быть использовано в методе getReturnFields. Также название метода функции должно содержать строку generate, чтобы функцию можно было увидеть на форме сопоставления полей целевой и промежуточной таблицы.
Пример DMFVendorEntityClass.GenerateParty()
/// <summary>
/// Generate Party information.
/// </summary>
/// <param name="_stagingToTarget">
/// Indicates if the method is called to generate target field values (true) or staging table values (false).
/// </param>
/// <returns>
/// Party information.
/// </returns>
[DMFTargetTransformationAttribute(true),DMFTargetTransformationDescAttribute("Функция, создающая запись субъекта"),
DMFTargetTransformationSequenceAttribute(1)
,DMFTargetTransFieldListAttribute([fieldStr(DMFVendorEntity,LanguageId),fieldStr(DMFVendorEntity,Name),fieldStr(DMFVendorEntity,NameAlias),fieldStr(DMFVendorEntity,PartyNumber),fieldStr(DMFVendorEntity,PartyType),fieldStr(DMFVendorEntity,FirstName),fieldStr(DMFVendorEntity,LastName),fieldStr(DMFVendorEntity,MiddleName),fieldStr(DMFVendorEntity,Gender),fieldStr(DMFVendorEntity,KnownAs),fieldStr(DMFVendorEntity,DunsNumber),fieldStr(DMFVendorEntity,ABC),fieldStr(DMFVendorEntity,NumberOfEmployees)])
]
public container GenerateParty(boolean _stagingToTarget = true)
{
DirOrganization dirOrganization;
DirOrganizationBase organizationBase;
DirDunsNumber dunsNumber;
container res;
DirPartyType partyType = DirPartyType::Person;
if (_stagingToTarget)
{
partyRecId = DMFParty::GenerateParty(entity, target.Party, DMFDataSourcePropertiesGlobal);
res = [partyRecId];
party = DirParty::constructFromPartyRecId(partyRecid);
}
else
{
if (target.Party)
{
if (!party)
{
partyRecId = target.Party;
party = DirParty::constructFromPartyRecId(target.Party);
}
if (party && party.parmType() == DirPartyType::Organization)
{
select firstonly NumberOfEmployees from dirOrganization where dirOrganization.RecId == partyRecId;
select firstOnly dunsNumberRecid from organizationBase
where organizationBase.Recid == partyRecId
join DunsNumber from dunsNumber
where dunsNumber.Recid == organizationBase.DunsNumberRecId;
}
}
res = [party.parmLanguageId(),
party.parmName(),
party.parmNameAlias(),
party.parmPartyNumber(),
enum2str(party.parmType()),
party.parmFirstName(),
party.parmLastName(),
party.parmMiddleName(),
enum2str(party.parmGender()),
party.parmKnownAs(),
dunsNumber.DunsNumber,
enum2str(party.parmABC()),
dirOrganization.NumberOfEmployees];
}
return res;
}
Метод getReturnFields
Метод getReturnFields используется для указания исходных или целевых полей по умолчанию для функций, которые используются для переноса данных. Параметры для метода:
_entity — название объекта.
_name — имя функции.
Возвращаемое значение – контейнер, в котором должны содержаться:
- Имя источника данных в запросе целевого объекта, который используется в методе
- Имя поля источника данных в запросе целевого объекта, которое должно быть инициализировано функцией
Пример DMFVendorEntityClass.getReturnFields().
/// <summary>
/// Creates field mapping between staging and target
/// </summary>
/// <param name="_entity">
/// A staging buffer.
/// </param>
/// <param name="_name">
/// A mapping method name.
/// </param>
/// <returns>
/// The list of fields as a container.
/// </returns>
public static container getReturnFields(Name _entity,MethodName _name)
{
DataSourceName dataSourceName = queryDataSourceStr(DMFVendorTargetEntity,VendTable);
container con = [dataSourceName];
Name fieldstrToTargetXML(FieldName _fieldName)
{
return DMFTargetXML::findEntityTargetField(_entity,dataSourceName,_fieldName).xmlField;
}
switch (_name)
{
case methodStr(DMFVendorEntityClass,GenerateParty) :
con += [fieldstrToTargetXML(fieldStr(VendTable,Party))];
break;
case methodStr(DMFVendorEntityClass,generateOffsetLedgerDimension) :
con += [fieldstrToTargetXML(fieldStr(VendTable,OffsetLedgerDimension))];
break;
case methodStr(DMFVendorEntityClass,generateDefaultDimension) :
con += [fieldstrToTargetXML(fieldStr(VendTable,DefaultDimension))];
break;
case methodStr(DMFVendorEntityClass,generateMainContactWorker) :
con += [fieldstrToTargetXML(fieldStr(VendTable,MainContactWorker))];
break;
case methodStr(DMFVendorEntityClass,generateMainContactWorker) :
con += [fieldstrToTargetXML(fieldStr(VendTable,MainContactWorker))];
break;
case methodStr(DMFVendorEntityClass, generateCompanyIdNAF) :
con += [fieldstrToTargetXML(fieldStr(VendTable, CompanyNAFCode))];
break;
case methodStr(DMFVendorEntityClass, generateTax1099Fields) :
con += [fieldstrToTargetXML(fieldStr(VendTable, Tax1099Fields))];
break;
case methodStr(DMFVendorEntityClass, generateLvPaymTransCodes) :
con += [fieldstrToTargetXML(fieldStr(VendTable, LvPaymTransCodes))];
break;
case methodStr(DMFVendorEntityClass,GeneratePostalAddress) :
case methodStr(DMFVendorEntityClass,GenerateElectronicLocation) :
case methodStr(DMFVendorEntityClass,generateAddressBook) :
case methodStr(DMFVendorEntityClass,generateDocumentStatus) :
break;
case methodStr(DMFVendorEntityClass,generateVendBankAccount) :
con += [fieldstrToTargetXML(fieldStr(VendTable, BankAccount))];
break;
default :
con = conNull();
}
return con;
}
Метод addStagingLink.
Используется для определения взаимосвязи между промежуточной таблицей и целевой таблицей, когда это отношение не может быть определено с помощью свойства связей на промежуточной таблице. Целевой запрос и промежуточная запись доступны в методе. Следовательно, связь между целью и организацией может быть добавлена с помощью кода.
Пример метода DMFEmployeeEntityClass.addStagingLink()
public Query addStagingLink(Query query, TableId _entityTableId, Common _staging)
{
QueryBuildDataSource qbd;
qbd = query.dataSourceTable(tableNum(HcmWorker));
qbd.addRange(fieldNum(HcmWorker,PersonnelNumber)).value(_staging.(fieldNum(DMFEmployeeEntity,PersonnelNumber)));
return query;
}
Запрос целевой сущности
Нужно создать запрос, который должен содержать все таблицы представляющие целевой объект.

Обработка поля RefRecId
Если целевая таблица содержит поля, которые являются RecIds из других таблиц. В этом случае есть два варианта:
- Добавить источник данных ссылочной таблицы к запросу целевой сущности.
- Создать функцию.
Добавление источника данных
Например, целевая таблица VendTable содержит поле VendExceptionGroup, которое представляет собой RecId таблицы VendExceptionGroup. В этом случае промежуточная таблица должна включать поле VendExceptionGroup. Таблица VendExceptionGroup также должна быть добавлена к запросу целевого объекта в источнике данных VendTable. Связь между VendTable и VendExecptionGroup должна быть указана вручную. Связь должна быть между полем RefRecId в VendTable и RecId на VendExceptionGroup. Промежуточное поле DMFVendorEntity.VendExecptionGroup должно быть сопоставлено с запросом целевого поля для DMFVendorTargetEntity(query). DS: VendExceptionGroup.VendExceptionGroup. Во многих случаях, если имя поля в целевом запросе совпадает с промежуточным полем, сопоставление выполняется автоматически. Вы также можете вручную сопоставить целевые поля с промежуточными полями.

Создание функции.
Связанные поля промежуточной таблицы с полем RefRecId целевой должны быть естественными ключами, по которым можно найти RecId таблицы, на которую ссылается целевая таблица. Создается метод в классе сущности для преобразования строкового поля (или набора полей) в RecId. Например, таблица CustTable содержит поле CompanyNAFCode, которое является RecId таблицы CompanyNAFCode. В этом случае нужно создать функцию в DMFCustomerEntityClass для преобразования строки (DMFCustomerEntity.CompanyIdNAF) в RecId (CompanyNAFCode.RecID). При создании функции, нужно создать группу полей для промежуточной таблицы, а возвращаемые поля для цели должны быть указаны в методе getReturnFields в классе сущности.
Пример
/// <summary>
/// This function generate companyIdNAF.
/// </summary>
/// <param name="_stagingToTarget">
/// Indicates if the method is called to generate target field values (true) or staging table values (false).
/// </param>
/// <returns>
/// companyIdNAF.
/// </returns>
[DMFTargetTransformationAttribute(true),DMFTargetTransformationDescAttribute("@DMF325"),
DMFTargetTransformationSequenceAttribute(7)
,DMFTargetTransFieldListAttribute([fieldStr(DMFCustomerEntity,CompanyIdNAF)])
]
public container generateCompanyIdNAF(boolean _stagingToTarget = true)
{
CompanyNAFCode companyNAFCode;
container res;
if (_stagingToTarget)
{
select firstOnly1 RecId from companyNAFCode where companyNAFCode.CompanyIdNAF == entity.CompanyIdNAF;
res = [companyNAFCode.RecId];
}
else
{
if (target.CompanyNAFCode)
{
select firstOnly1 CompanyIdNAF, RecId from companyNAFCode where companyNAFCode.RecId == target.CompanyNAFCode;
}
res = [companyNAFCode.CompanyIdNAF];
}
return res;
}
При изменении состава полей на целевой таблице, добавлении нового источника данных в запрос целевой сущности или создании новой функции нужно обновлять (удалять и снова создавать) Целевые объекты (MainMenu/Структура импорта и экспорта данных/Настройка/Целевые объекты).
Все комментарии
Чтобы оставить комментарий, необходимо войти или зарегистрироваться.
Пока нет комментариев. Будьте первым!