web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

News and Announcements icon
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested Answer

Posttargetprocess and Posttargetprocesssetbased during import data entity

(0) ShareShare
ReportReport
Posted on by 536
Hi team,
 
Pls let me know what is the difference between posttargetprocess and posttargetprocesssetbased method in import data entity in d365fo.
 
Is there any condition to call this method? I mean at a time any one of the method getting called or both are getting called during import.
 
Pls advise, thanks 
Categories:
I have the same question (0)
  • Suggested answer
    vishalsahijwani Profile Picture
    228 on at
    Hi @CU10121822-0 , 
     
    Let us try to understand this in a simplified manner.
     

    Both postTargetProcess and postTargetProcessSetBased are hook methods on a data entity. They run after data has been pushed from the staging table into the actual target table(s) during import. You override them when you want to add extra logic after records land in the real table (like updating a related table, triggering a workflow, logging something, etc.)
    The difference is which import mode triggers them.

    postTargetProcess
    This runs when the import uses record-by-record processing (also called RBO — Record By Object).
    In this mode, D365 loops through each staging record one at a time, creates/updates the actual record using normal X++ (insert(), update(), business logic, validations, etc.), and after each record is processed, it calls postTargetProcess for that record.
    Since it's per-record, you get the actual buffer/record easily and can act on it individually.
     
    postTargetProcessSetBased
    This runs when the import uses set-based processing — meaning D365 skips the one-by-one X++ record loop and instead does a bulk SQL operation (like a single INSERT INTO...SELECT) to move all staging rows into the target table at once.
    This is much faster for large volumes, but because it's pure SQL and not going through normal record-by-record business logic, the framework calls postTargetProcessSetBased once, after the whole set-based operation is done — not per record.
     
    Let us try to understand this through a basic example : - 
     
    postTargetProcess is manually handing over items to someone one at a time, and every time you hand one over, you also whisper a quick instruction ("also update this").
     
    postTargetProcessSetBased is dumping the whole box of items in one go, and only giving one instruction at the very end for the whole batch.
     
    Now your main question — do both get called, or just one?

    Only one gets called — never both — for a given import run of that entity.

    It depends on which processing mode the entity/import actually used, which is decided based on:
     
    Whether "Set-based processing" is enabled on the entity/import project execution settings.
    Whether the entity supports set-based processing at all — not all entities can use it. If the entity has complex business logic, validations, or per-record events that must fire, D365 won't allow set-based mode, and it'll silently fall back to record-by-record.
     
    So if the run happens in record-by-record mode → only postTargetProcess fires (once per record).
    If the run happens in set-based mode → only postTargetProcessSetBased fires (once for the whole batch).
     
    Note
    If you're customizing an entity and want your logic to work correctly no matter which mode gets picked at runtime (since the same entity might sometimes run set-based and sometimes fallback to record-based, depending on data volume/settings), it's safest to override both methods with equivalent logic — otherwise your custom logic might silently not run if the import decides to use the other mode.
     
     
    Let us now try to understand this through a x++ code example : - 
     
    Here's a simple example. Let's say you want to update a custom field CustLastImportedDate on the CustTable whenever customer records are imported through a data entity.
     
    // Extension class for the data entity (e.g., CustCustomerEntity)
    [ExtensionOf(tableStr(CustCustomerEntity))]
    final class CustCustomerEntity_Extension
    {
        // Called when import runs in RECORD-BY-RECORD mode
        public void postTargetProcess(Common _sourceStagingBuffer, Common _targetBuffer)
        {
            next postTargetProcess(_sourceStagingBuffer, _targetBuffer);
            CustTable custTable = _targetBuffer as CustTable;
            if (custTable)
            {
                this.updateLastImportedDate(custTable.RecId);
            }
        }
        // Called when import runs in SET-BASED mode
        public void postTargetProcessSetBased(DataEntityRuntimeContext _dataEntityRuntimeContext,
                                                RefTableId _targetTableId,
                                                RefRecId _fromRecId,
                                                RefRecId _toRecId)
        {
            next postTargetProcessSetBased(_dataEntityRuntimeContext, _targetTableId, _fromRecId, _toRecId);
            // Loop through the range of RecIds that got inserted/updated in this batch
            CustTable custTable;
            while select custTable
                where custTable.TableId == _targetTableId
                   && custTable.RecId >= _fromRecId
                   && custTable.RecId <= _toRecId
            {
                this.updateLastImportedDate(custTable.RecId);
            }
        }
        // Shared logic used by both methods, so you write it only once
        private void updateLastImportedDate(RecId _custTableRecId)
        {
            CustTable custTable = CustTable::findRecId(_custTableRecId, true); // forUpdate = true
            ttsbegin;
            custTable.CustLastImportedDate = DateTimeUtil::date(DateTimeUtil::getSystemDateTime());
            custTable.update();
            ttscommit;
        }
    }
     
     

    Important points to follow in the above code example


    1. Both methods call the same shared private method (updateLastImportedDate) — this way you write your actual business logic only once, and both hooks just feed it the right record(s).

    2. postTargetProcess gives you a direct buffer (_targetBuffer), since it's per-record.

    3. postTargetProcessSetBased does not give you a buffer — it only gives you a range of RecIds (_fromRecId to _toRecId) that were affected in that bulk operation. So you have to query the table yourself for records in that range.

    4. Always wrap updates in ttsbegin/ttscommit since you're doing DB writes outside the normal insert/update flow.

    5.  

     

    In set-based mode, you're working with a range of RecIds, not individual field-level info from staging — so if your logic needs specific staging data (like a source system value not present in the target table), set-based mode makes that harder to access. In such cases, you may need to either:


    • Force the entity to always use record-by-record mode for that scenario, or

    • Query the staging table directly using the RecId range as a filter.
     
     
    Please let us know if this makes sense to you also please post if you have any questions or doubts we will be happy to discuss. 
     
     
    All the best !!!

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Season of Sharing Community Challenge Winners!

Congratulations to our community stars!

Women in Power Builds Momentum

Expanding mentorship, skilling, and AI innovation

Congratulations to the June Top 10 Community Leaders

These are the community rock stars!

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 407 Super User 2026 Season 1

#2
Subra Profile Picture

Subra 394

#3
Martin Dráb Profile Picture

Martin Dráb 275 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans