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 :
Dynamics 365 Community / Blogs / Hardik’s Dynamics Dojo / Two Data Entity Methods Eve...

Two Data Entity Methods Every D365 Developer Should Know

HardikPatel523 Profile Picture HardikPatel523 234

"But it works from the UI... Why is it failing during import?" 🤔

If you've worked with Data Entities long enough, you've probably faced this situation:
You add some business logic in `modifiedField()`.
You test from the form.
Everything works beautifully.
You deploy confidently.
Then someone imports 50,000 sales lines through DMF and suddenly...
Nothing happens.
Profit calculations are wrong.
Derived fields are empty.
And now everyone is looking at you like you personally broke Finance and Operations.
Fun times.
If this sounds familiar, welcome to one of the most common Data Entity traps in D365 F&O.

The Problem

Let's take a simple example.
Suppose you added a custom field called: ProfitPercent on the `SalesLine` table.
Whenever Sales Price or Cost Price changes, you calculate Profit Percentage.
So naturally, you put the logic in `modifiedField()`.
public void modifiedField(FieldId _fieldId)
{
    // Calculate Profit %
}
User changes values from the UI?
✅ Works
User edits a sales line?
✅ Works
User imports data through DMF?
❌ Doesn't work
OData update?
❌ Doesn't work
Custom integration?
❌ Doesn't work
Suddenly your "perfect solution" isn't so perfect anymore.
If your business logic exists only in modifiedField(), you're solving the UI problem, not the Data Entity problem.

Why Does This Happen?

Because Data Entity processing is very different from user interaction.
When a user updates a field from a form:

User changes value

modifiedField() executes

Business logic runs

Record saved

Life is good.
But during Data Entity processing:

Entity receives data

Mappings are applied

Table buffers are populated directly

validateField()
validateWrite()
insert()
update()

Record saved

Notice something missing?

modifiedField()

It's usually skipped.
Why?
Because no human is sitting there clicking on fields.
The framework is directly pushing data into buffers.
No form.
No user interaction.
No modifiedField.
No magic.

Think About It Like Swiggy 🚚

Imagine you're running a restaurant.
Normally a customer walks in and tells the waiter: "Please make my food extra spicy."
The waiter hears it and informs the kitchen.
That's your `modifiedField()`.
Now imagine Swiggy sends 5,000 online orders directly into the kitchen system.
The waiter never sees them.
The kitchen receives the order directly.
Should you still expect the waiter to communicate the instructions?
Of course not.
That's exactly what happens with Data Entities.
Your UI logic (waiter) is bypassed.
The system talks directly to the kitchen (table buffers).

Enter insertEntityDataSource() and updateEntityDataSource()

These two methods are specifically designed for Data Entity processing.

insertEntityDataSource()
updateEntityDataSource()


The best part?
They execute per datasource.
Meaning if your entity contains:
  • SalesTable
  • SalesLine
  • InventDim
  • CustTable
You can target exactly the datasource you want.
No guessing.
No hacks.
No "let me put it in table update and hope for the best."

What Do We Get?

These methods provide:

DataEntityRuntimeContext
DataEntityDataSourceRuntimeContext


And from datasource context we can get the actual table buffer.

SalesLine salesLine = _dataSourceCtx.getBuffer();

Now we finally have access to the record we actually want to modify.

Advanced Example #1: Calculating Profit Percentage

Let's say ProfitPercent should only be calculated during Data Entity imports.
Maybe external integrations send prices and you want ProfitPercent refreshed automatically.
public boolean insertEntityDataSource(
    DataEntityRuntimeContext           _entityCtx,
    DataEntityDataSourceRuntimeContext _dataSourceCtx)
{
    switch (_dataSourceCtx.name())
    {
        case dataEntityDataSourceStr(SalesOrderLineV2Entity, SalesLine):

            SalesLine salesLine = _dataSourceCtx.getBuffer();

            salesLine.ProfitPercent = (salesLine.SalesPrice - salesLine.CostPrice) / 100;

            break;
    }

    next insertEntityDataSource(_entityCtx, _dataSourceCtx);
}
Notice something important.
We are only setting the value.
We are not calling insert.
We are not calling update.
The framework already handles that, since we wrote code before next call.
Sometimes the best code is the code you don't write.

The Real Power: Unmapped Fields

Now let's look at a scenario where many developers get stuck.
Suppose your Data Entity contains an unmapped field: AutoCreateProd
When the import file contains:
AutoCreateProd = Yes
you want to automatically create a Production Order.
Here's the problem.
This field exists only on the Data Entity.
Not on SalesLine.
Not in the database.
Not anywhere else.
So where do you read it?
Certainly not from table insert().
The table has no idea this field ever existed.
This is exactly where datasource methods shine.

Advanced Example #2: Auto-Creating Production Orders

public boolean insertEntityDataSource(
    DataEntityRuntimeContext           _entityCtx,
    DataEntityDataSourceRuntimeContext _dataSourceCtx)
{
    boolean ret = next insertEntityDataSource(_entityCtx, _dataSourceCtx);

    switch (_dataSourceCtx.name())
    {
        case dataEntityDataSourceStr(SalesOrderLineV2Entity, SalesLine):

            SalesLine salesLine = _dataSourceCtx.getBuffer();

            if (NoYes::Yes == this.CsSlsPrdAutoCreateProd)
            {
                this.createProductionOrder(salesLine);
            }

            break;
    }

    return ret;
}

private void createProductionOrder(
        SalesLine _salesLine)
{
    // Actual production order logic
}
Try doing this from table insert().
You can't.
Because the table never receives that unmapped field.

Why Not Use Table insert() or update()?

This is probably the biggest misunderstanding.
Many developers think: "I'll just put everything in table insert/update."
Sometimes that's correct.
But not always.
Let's compare.

RequirementTable Insert/UpdateEntity Datasource Methods
Run for all record creation
Run only for Data Entity imports
Access unmapped entity fields
Access datasource buffer directlyN/A
Integration-specific logic

Rule of thumb

If the logic belongs to the table, put it in the table.
If the logic belongs to the Data Entity process, put it in the Data Entity.

Common Mistakes I See

Mistake #1

Putting import-specific logic inside `modifiedField()`.
Works in UAT from UI.
Fails in production import.
Classic.

Mistake #2

Adding everything into table `insert()`.
Now every integration, batch job, X++ process and custom service executes the same logic.
Unexpected side effects incoming.

Mistake #3

Forgetting datasource-specific processing.
Remember: _dataSourceCtx.name() exists for a reason.
Always check which datasource you're handling.

Mistake #4: The Dangerous Copy-Paste Trap 😄

We've all done it.
You need similar logic in another Data Entity.
So you copy code from one entity, paste it into another, change a few things, run a quick test, and everything works.
For example: case dataEntityDataSourceStr(SalesOrderLineV2Entity, SalesLine):
You copied this from another entity extension but forgot to change: SalesOrderLineV2Entity to your current entity.
Surprisingly, the code may still work.
Why?
Because `dataEntityDataSourceStr()` ultimately resolves to the datasource name, and if both entities happen to use a datasource with the same name (`SalesLine`), your condition may still match.
So everybody is happy.
Code review passes.
Testing passes.
Production runs fine.
Then six months later someone modifies the datasource name in the original entity.
Suddenly your completely unrelated entity stops executing its logic.
Now comes the fun part: "Nothing changed in my entity."
Technically true.
But your code was accidentally depending on metadata from another entity.

Reality Check

Junior Developer  - "modifiedField works. Ship it."
Senior Developer - "Will this also work through DMF, OData and integrations?"
Architect  - "Which layer actually owns this business rule?"

The difference isn't coding.
The difference is thinking about all entry points.

Final Thoughts

✔ Data Entities don't behave like forms
✔ modifiedField() is usually bypassed during imports
✔ insertEntityDataSource() and updateEntityDataSource() execute per datasource
✔ They provide access to datasource buffers
✔ They are perfect for integration-specific logic
✔ They are extremely useful when working with unmapped entity fields
✔ Not every business rule belongs in table insert/update

"In D365 F&O, the question isn't 'Can I write the code here?' The real question is 'Should this logic live here?'"

Comments