Bypassing Table Validations During Data Entity Imports using a Context Class

Context class


The Problem

When importing data via Data Entities (DIXF or OData), the system often triggers validateWrite() on the underlying tables. While these validations are essential for UI-based entries, they can sometimes block bulk imports or perform redundant checks that slow down the process. We need a way to tell the table: "Hey, I'm currently being called by a Data Entity, so skip this specific check."

The Solution: A Scoped Context Class

The solution involves three parts: a Context Class to hold the state, an Entity Override to set the state, and a Table Override to read the state.

Step 1: Create the Context Class

This class implements System.IDisposable so it can be used in a using block. This ensures that the global instance is cleared (disposed) as soon as the import operation finishes, preventing "state leakage" to other processes.

public final class RebateAgreementHeaderEntityContext implements System.IDisposable
{
    private static RebateAgreementHeaderEntityContext instance;
    private boolean isDataImporting;
    // Standard Singleton/Context pattern
    public void dispose()
    {
        instance = null;
    }
    private void new()
    {
        if (instance)
        {
            throw error(Error::wrongUseOfFunction(funcName()));
        }
        instance = this;
    }
    public static RebateAgreementHeaderEntityContext construct()
    {
        return new RebateAgreementHeaderEntityContext();
    }
    public static RebateAgreementHeaderEntityContext current()
    {
        return instance;
    }
    public boolean parmDataImporting(boolean _dataImporting = isDataImporting)
    {
        isDataImporting = _dataImporting;
        return isDataImporting;
    }
}

Step 2: Initialize the Context in the Data Entity

We override insertEntityDataSource on the Data Entity. By wrapping the next call in a using block, the context is active only for the duration of that specific insert operation.

public boolean insertEntityDataSource(DataEntityRuntimeContext _entityCtx, DataEntityDataSourceRuntimeContext _dataSourceCtx)

{

    boolean ret;


    // The 'using' block ensures dispose() is called automatically at the '}'

    using (RebateAgreementHeaderEntityContext context = RebateAgreementHeaderEntityContext::construct())

    {

        context.parmDataImporting(true);

          

        // Any table-level code called inside this 'next' will see the context

        ret = next insertEntityDataSource(_entityCtx, _dataSourceCtx);

    }                

    

    return ret;

}


Step 3: Consume the Context in the Table Level

In the table's validateWrite(), we check if a context exists and if isDataImporting is true.

public boolean validateWrite()

{

    boolean ret = next validateWrite();

    // Check if we are running within our custom context

    RebateAgreementHeaderEntityContext context = RebateAgreementHeaderEntityContext::current();    

    boolean isImporting = (context && context.parmDataImporting());

    if (ret && !isImporting)

    {

        // Only perform this validation if NOT importing via the entity

        if (this.SomeField == "")

        {

            ret = checkFailed("Validation failed for manual entry.");

        }

    }

    return ret;

}



Comments