Skip to main content

Notifications

Announcements

No record found.

Dynamics 365 Community / Blogs / Learn with Subs / Modifying a DMF data entity...

Modifying a DMF data entity query dynamically, from another query

Subhad365 Profile Picture Subhad365 7 User Group Leader
 


Problem statement 
Have you ever came across a situation where you needed to run your data entity through a batch, and in your batch you have a very complex composite query (where the query ranges could be anything -- the user can keep adding new ranges to the query) and you need pass on the query range values to your data entity query. I bet you must have faced this: say, your data contract is having an AOT query called PurchContractQry where you have PurchTable, Purchline, InventDim, PurchParmLine and a litter of related tables. You have an entity that does have a different query (as you know Data entities store queries as packed data in DMFDefinitionGroupEntity)-- how could you possibly make the ranges flow to your Entity, then?
The following blog explains the same.
As an example: we have created a Data entity called D365DataEntityPurchExport, which exports records based on the ranges supplied in a query coming from a contract Class, called PurchContractQry. We need to get the ranges which user is selecting/enetering and pass them on to the entity and run it accordingly. 
Step 1: in your service class, you can get query from dataContract:
_contract.getQuery();
You can also get the query of your entity by simply saying:
Query    purchEnttQuery = new Query(DMFUtil::getDefaultQueryForEntityV3(_entityName));
Where _entityName is the name of the Entity you are using (in our case, it's DMFDefinitionGroupEntity).
Hence you can create a new query for your entity and get the contents of your query like this:
purchEnttQuery = this.addAdditionalRanges(_contract.getQuery(), purchEnttQuery ) ;
We are going to create a new method to get the ranges from our contract class, like this:
private Query addAdditionalRanges(Query _contractQry, Query    _entityQuery)
    {
        Counter totalDSources = _contractQry.dataSourceCount();
        QueryBuildDataSource qbdsPurch = _entityQuery.dataSourceTable(tableNum(D365DataEntityPurchExport));
        for(int ds =1; ds<= totalDSources ; ds++)
        {
            QueryBuildDataSource    qbds = _contractQry.dataSourceNo(ds);
            Counter totalRanges = qbds.rangeCount();
            for(int r =1; r<= totalRanges; r++)
            {
                QueryBuildRange qbr =  qbds.range(r);
                SysQuery::findOrCreateRange(qbdsPurch , fieldName2Id(tableNum(D365DataEntityPurchExport), qbr.fieldName())).value(qbr.value());
            }
        }
        return _entityQuery;
    }
Where dynamically your are setting the name of the query ranges in your data entity, by getting the values from your contract class Query.
Step2: We can execute an entity like this very easily:
            DMFEntityExporter exporter = new DMFEntityExporter();
            SharedServiceUnitFileID fileId = exporter.exportToFile(
                                           entityName,
                                           _dataContract.parmDefinitionGroupName(),
                                           '',
                                           DXCMVTExportMacros::csvFile,
                                           #FieldGroupName_AllFields,
                                           conNull(),                                           
                                           curExt(),
                                           null,               
                                           true,                
                                           false
                                           );
We can add this in the process method of our Service class. But the problem with this method is: it doesn't update the query you want it to execute -- it will make the entity to execute default version of the query. 
Why?
Well, look at the following code inside the above method:




Which means it will update the query of the entity, only when the definition group provided is blank. But what if, your definiton group is not blank -- purposely you want to execute your entity against any defintion group? 
Step 3: For this -- you can force the Definiton group entity to accept the packed query like this, before hand:
DMFDefinitionGroupEntity definitionGroupEntity = DMFDefinitionGroupEntity::find(_contract.parmDefinitionGroupName(), 
                                                                                        _entityName, 
                                                                                        true);
        if (definitionGroupEntity)
        {
            ttsbegin;
            definitionGroupEntity.QueryData = _query.pack();
            definitionGroupEntity.update();
            ttsCommit;
        }
As a result, the defintion group will be updated with the query value and be assigned to the entity:




 
So much for today -- see you soon :)

Comments

*This post is locked for comments