AX / D365FO – Preventing Auto-Creation of Empty Child Records in D365FO Join Forms with Chain of Command

When you’re working with two joined DataSources on a Dynamics 365 Finance & Operations form—using an OuterJoin for the child—you’ll often find that inserting or editing a parent record automatically creates an unwanted, empty child record. That placeholder can clutter the UI and confuse your users. Instead of fighting form properties or scattershot event handlers, you can take full control at runtime by extending the child DataSource’s key methods via Chain of Command.


The Core Idea

Override the child DataSource’s lifecycle methods so they do nothing. Specifically, you’ll target:

  1. create() – normally allocates a new buffer when you start adding a child
  2. validateWrite() – runs pre-write validation logic
  3. write() – performs the actual insert or update

By intercepting and bypassing these methods, you ensure that no buffer or DML ever occurs for the child—even though the OuterJoin still loads existing records for display.

Code Example

Create an extension class in your Visual Studio project under Forms → MyForm → DataSources → SecondaryDS:

// File: MyFormSecondaryDSExtension.xpp
[ExtensionOf(formDataSourceStr(MyForm, SecondaryDS))]
public final class MyFormSecondaryDSExtension
{
    /// <summary>
    /// Block automatic buffer creation when the parent inserts/edits.
    /// </summary>
    public void create(boolean _append = false)
    {
        // Intentionally empty: no super.create(), so no new buffer.
    }

    /// <summary>
    /// Skip any validation before write.
    /// </summary>
    public boolean validateWrite()
    {
        return true;  // Bypass base validation logic
    }

    /// <summary>
    /// Prevent any persistence to the database.
    /// </summary>
    public void write()
    {
        // Intentionally empty: no super.write(), so no insert/update.
    }
}

  1. Add an Extension: In Visual Studio, right-click your form and choose Add → Extension.
  2. Select SecondaryDS: Navigate to your child datasource.
  3. Paste the Code: Replace the generated stub with the snippet above.
  4. Build & Deploy: No form-property tweaks needed.

How It Works

  • create() override
    By omitting the next() (or super.create()) call, the framework never allocates a new buffer for a child record when you manipulate the parent.
  • validateWrite() override
    Returning true short-circuits any built-in DML validation, ensuring no pre-write triggers or checks force an insert.
  • write() override
    With no invocation of next(), the actual database insert or update is skipped entirely.

Existing child records still appear thanks to your OuterJoin, but there will never be an empty placeholder cluttering the grid.


Benefits

  • Zero Form-Property Changes
    Keep your design-time settings clean—no need to adjust InsertIfEmpty, LinkType, or other flags.
  • Full Runtime Control
    Code overrides always win, regardless of later form changes or environment quirks.
  • Performance Gain
    Eliminating unnecessary buffer allocations and DML calls reduces overhead.
  • Maintainability
    Encapsulating the behavior in a single extension class makes your intent clear to future maintainers.

Leave a comment