I read the API's documentation in https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/data-management-api , and from my understanding this is the recommended API for importing large amounts of data without making specific configurations in a Finance and Operations instance - compared to the Recurring integrations API where you need to configure 'data projects' (please correct me if I am wrong). I understand the import and export flow as a concept, but I have several questions that I would appreciate an answer. Can you generate a data package manually? Manifest, data files etc? Is there some specific format/template that someone can use to generate data packages?
To give a concrete example, if I am currently creating a 'People' entity by making a POST request to:
POST dynamics.com//data/People
{
"@odata.type": "#Microsoft.Dynamics.DataEntities.Person",
"FirstName": "First",
"LastName": "Last",
"NameSequenceDisplayAs": "FirstMiddleLast",
"MiddleName": "Middle"
}
How can I create a data package with multiple 'People' manually and import it? My problem is creating the data package specifically, I understand how to make the HTTP requests to the API.
Thank you very much for the explanation.
I did not factor in OData API rate limitations (throttling) when comparing performances, so that would explain my experience with performance.
------------
I wanted to ask some last questions if possible.
In this case where we are importing Employee data, as mentioned previously, the Personnel Number is auto-generated when creating with OData, but with imports we need to specify all key fields (since it will default to empty with Data management API). I have created the data file with employee data, and want to generate the Personnel Numbers manually (through maybe random integer code generation or similar).
1) Is there any simple way to guarantee the uniqueness of the keys compared to existing keys in the database if for example I generate a random Personnel Number through code? From my understanding this entity has a composite primary key, so the composite key needs to be unique, and this seems like a complex issue since I need to check every existing record's composite key.
2) Or do I only need to do this unique key check for the records in the data file itself and not any existing employees in the platform?
3) Is this a typical use-case when importing large amounts of data - meaning do other clients generate all their data including primary keys before importing with this API? Or do they do some comparison by exporting the data firstly? I am not sure if I am doing something wrong here, generating the PersonnelNumbers seems like something clients should not need to do manually.
4) I assume the Recurring integrations API functions similarly with staging tables and would have the same key problem?
The difference in behavior is that data management uses staging tables, the OData service is not.
Your experience about performance is strange; I don't know what's going on there.
No problem, it is thanks to your guidance that I got this far.
I am still confused though, why does the Data management API require more fields than the OData API when creating an entity? Or is it because the Data management API is for "importing" existing data while with OData you are "creating" new data and some of the "new" data is auto-generated?
The execution job for importing 5000 records took about half a hour with the Data management API, while it takes less than a few minutes to create 5000 records with the OData batch endpoint. I was under the assumption that the Data management API was the recommended API for working with large amounts of data, but scheduling, running and monitoring the execution from an outside program for this API's jobs for hours seems pointless when you can send all the data with the OData batch endpoint. Or is there something I am missing about this and the Recurring integration APIs usefulness?
Ah, sorry, it seems I was looking at a wrong entity (employment instead of employee).
Thank you a lot, I tested and successfully managed to create 10 records by adding PersonnelNumber.
I actually tested the data fields in OData and managed to successfully create a record (normal and batch endpoint). The PersonnelNumber was auto-generated from when I checked the UI. Is this behavior normal/expected - a difference in the APIs?
POST /data/Employees/ HTTP/1.1 { "@odata.type": "#Microsoft.Dynamics.DataEntities.Employee", "EmploymentLegalEntityId": "dat", "EmploymentStartDate": "2020-02-02T05:00:00.000Z", "FirstName": "testA", "NameAlias": "testA" } |
---
Edit: Not sure how normal this is, I am now testing importing 5000 records from a CSV file, and this API is rather slow compared to OData. 'Executing' is taking a lot of time.
The error says that you're violating the uniqueness of the primary key of HcmEmploymentStaging table, which is a combination of PersonnelNumber, EmploymentLegalEntityId, EmploymentStartDate and EmploymentEndDate.
The field you've mapped to your file is EmploymentLegalEntityId. That'll be the same for both records, and all other key fields will be empty, therefore this forms the same and the database rejects the duplicate.
You can't simply ignore key fields.
Thank you very much for all the help.
The /metadata/DataEntities is exactly what I was looking for and you are right that the project is automatically created.
I successfully created a package and managed to import/start executing it, but it is always failing.
I did notice that the export manifest files have a QueryData section, but I cannot find what the encoding is or if/what needs to be inserted into this field.
<QueryData>4a012f270000110001e649010000000a4de9030000862b00008c2b0000882b00
008b2b00000000840444006900720050006500720073006f006e0045006e0074
006900740079000000110001e803240044006900720050006500720073006f00
6e0045006e0074006900740079005f0031000000e20920004400690072005000
6500720073006f006e0045006e0074006900740079000000094de8030000f319
000000920402001100010000ffffffffffffffff9b04ffff9a04ffff00000000
000001ffffffff00900500000000000000000000000000000000000000000000
0000000000000000</QueryData>
I checked the execution log, but I am not sure what constraints I am violating with my data.
SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80004005. An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80004005 Description: "The statement has been terminated.". An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80004005 Description: "Violation of PRIMARY KEY constraint 'I_2689STAGINGIDX'. Cannot insert duplicate key in object 'dbo.HCMEMPLOYEESTAGING'. The duplicate key value is [PII data removed].". SSIS Error Code DTS_E_INDUCEDTRANSFORMFAILUREONERROR. The "OLE DB Destination.Inputs[OLE DB Destination Input]" failed because error code 0xC020907B occurred, and the error row disposition on "OLE DB Destination.Inputs[OLE DB Destination Input]" specifies failure on error. An error occurred on the specified object of the specified component. There may be error messages posted before this with more information about the failure. SSIS Error Code DTS_E_PROCESSINPUTFAILED. The ProcessInput method on component "OLE DB Destination" (473) failed with error code 0xC0209029 while processing input "OLE DB Destination Input" (486). The identified component returned an error from the ProcessInput method. The error is specific to the component, but the error is fatal and will cause the Data Flow task to stop running. There may be error messages posted before this with more information about the failure. Failed to insert record into staging table. The keys of the record are DEFINITIONGROUP, EMPLOYMENTENDDATE, EMPLOYMENTLEGALENTITYID, EMPLOYMENTSTARTDATE, EXECUTIONID, PARTITION, PERSONNELNUMBER. Duplicate records must be removed from the file prior to import.-SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80004005. An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80004005 Description: "The statement has been terminated.". An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80004005 Description: "Violation of PRIMARY KEY constraint 'I_2689STAGINGIDX'. Cannot insert duplicate key in object 'dbo.HCMEMPLOYEESTAGING'. The duplicate key value is [PII data removed].". '0' 'Employee' record(s) inserted in staging |
PackageHeader.xml
<DataManagementPackageHeader xmlns:i="">www.w3.org/.../XMLSchema-instance" xmlns="">schemas.microsoft.com/.../DataManagement"> <Description>TEST_GROUP_NAME</Description> <ManifestType>Microsoft.Dynamics.AX.Framework.Tools.DataManagement.Serialization.DataManagementPackageManifest</ManifestType> <PackageType>DefinitionGroup</PackageType> <PackageVersion>2</PackageVersion> </DataManagementPackageHeader> |
Manifest.xml
<DataManagementPackageManifest xmlns:i="">www.w3.org/.../XMLSchema-instance" xmlns="">schemas.microsoft.com/.../DataManagement"> <DefinitionGroupName>TEST_GROUP_NAME</DefinitionGroupName> <Description></Description> <PackageEntityList> <DataManagementPackageEntityData> <DefaultRefreshType>FullPush</DefaultRefreshType> <Disable>false</Disable> <EntityMapList> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>EMPLOYMENTLEGALENTITYID</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>EMPLOYMENTLEGALENTITYID</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>FIRSTNAME</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>true</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>FIRSTNAME</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>NAMEALIAS</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>true</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>NAMEALIAS</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>EMPLOYMENTSTARTDATE</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>EMPLOYMENTSTARTDATE</XMLField> </EntityMap> </EntityMapList> <EntityName>Employee</EntityName> <EntityTransformList i:nil="true"></EntityTransformList> <ExcelSheetName></ExcelSheetName> <ExecutionUnit>1</ExecutionUnit> <FailExecutionUnitOnError>true</FailExecutionUnitOnError> <FailLevelOnError>true</FailLevelOnError> <InputFilePath>Employee.csv</InputFilePath> <LevelInExecutionUnit>1</LevelInExecutionUnit> <QueryData></QueryData> <QueryFilter i:nil="true"></QueryFilter> <RunBusinessLogic>true</RunBusinessLogic> <RunBusinessValidation>true</RunBusinessValidation> <SampleFilePath></SampleFilePath> <SequenceInLevel>1</SequenceInLevel> <SourceFormat>CSV-Unicode</SourceFormat> <TargetEntity>HcmEmployeeEntity</TargetEntity> <ValidationStatus>Yes</ValidationStatus> </DataManagementPackageEntityData> </PackageEntityList> <ProjectCategory>0</ProjectCategory> <RulesData i:nil="true"></RulesData> </DataManagementPackageManifest> |
Employee.csv
EMPLOYMENTLEGALENTITYID,FIRSTNAME,NAMEALIAS,EMPLOYMENTSTARTDATE dat,testA,testA,2020-02-02 dat,testB,testB,2020-02-02 |
OData uses names defined in "Public Entity Name" property of data entities. If I understand it correctly, you want to get actual name of an entity name from its public name. You can use the the metadata service ([F&O URL]/metadata/DataEntities).
Legal entity ID is the company (USMF, DAT...) to which you want to import the data.
Regarding DefinitionGroupId, I think it's just a name. The project doesn't need to be created up-front; it'll be created based on the information in the manifest.
I think I got this somewhat working.
I created a PackageHeader.xml, manifest.xml and Entity.csv file following an export template.
manifest.xml
<DataManagementPackageManifest xmlns:i="">www.w3.org/.../XMLSchema-instance" xmlns="">schemas.microsoft.com/.../DataManagement"> <DefinitionGroupName>TEST_GROUP_NAME</DefinitionGroupName> <Description></Description> <PackageEntityList> <DataManagementPackageEntityData> <DefaultRefreshType>FullPush</DefaultRefreshType> <Disable>false</Disable> <EntityMapList> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>FIRSTNAME</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>FIRSTNAME</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>MIDDLENAME</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>MIDDLENAME</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>LASTNAME</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>LASTNAME</XMLField> </EntityMap> <EntityMap> <ArrayIndex>0</ArrayIndex> <EntityField>NAMESEQUENCEDISPLAYAS</EntityField> <EntityFieldConversionList i:nil="true"></EntityFieldConversionList> <IsAutoDefault>false</IsAutoDefault> <IsAutoGenerated>false</IsAutoGenerated> <IsDefaultValueEqualNull>false</IsDefaultValueEqualNull> <UseTextQualifier>false</UseTextQualifier> <XMLField>NAMESEQUENCEDISPLAYAS</XMLField> </EntityMap> </EntityMapList> <EntityName>People</EntityName> <EntityTransformList i:nil="true"></EntityTransformList> <ExcelSheetName></ExcelSheetName> <ExecutionUnit>1</ExecutionUnit> <FailExecutionUnitOnError>true</FailExecutionUnitOnError> <FailLevelOnError>true</FailLevelOnError> <InputFilePath>Data.csv</InputFilePath> <LevelInExecutionUnit>1</LevelInExecutionUnit> <RunBusinessLogic>true</RunBusinessLogic> <RunBusinessValidation>true</RunBusinessValidation> <SampleFilePath></SampleFilePath> <SequenceInLevel>1</SequenceInLevel> <SourceFormat>CSV-Unicode</SourceFormat> <ValidationStatus>Yes</ValidationStatus> </DataManagementPackageEntityData> </PackageEntityList> <ProjectCategory>0</ProjectCategory> <RulesData i:nil="true"></RulesData> </DataManagementPackageManifest> |
Are there any docs that explain the various fields in the manifest.xml file? I am not certain which are required to import the package, or their exact functionality and valid values.
There was an additional field called 'TargetEntity'. I am getting the EntityField value from the OData $metadata endpoint. Is there any way to get the target entity from the entity name?
<TargetEntity>DirPersonEntity</TargetEntity>
I also noticed that to ImportFromPackage, I need to specify 'definitionGroupId' and 'legalEntityId'
definitionGroupId - The name of the data project for import. I assume this should match my 'TEST_GROUP_NAME' and serves no actual purpose? Or is this API unusable unless you first create a project in the UI with the same name?
legalEntityId - 'The legal entity for the data import.' I am not certain what the value for this should be?
Thank you for the confirmation. Yes, I did actually mean generating them through code.
I will test exporting some packages and see to find some patterns and hopefully generate a reusable template for different entities.
André Arnaud de Cal...
292,074
Super User 2025 Season 1
Martin Dráb
230,900
Most Valuable Professional
nmaenpaa
101,156