0

In October 2025 and beyond it’s important to know what is x++  (x plus plus) for Dynamics 365 Finance and Operations programming and development.

A join example in X++ of datasource query Dynamics 365 Finance and Operations Training for Developers October 2025 Dynamics Edge
X++ query join datasource example October 2025 Dynamics Edge

Dynamics 365 is a family of business apps that share a common cloud foundation but focus on different problems. Sales is built for managing leads, opportunities, pipeline, quotes, and forecasting. Customer Service focuses on cases, SLAs, knowledge, and omnichannel support. Field Service handles work orders, technician schedules, parts usage, and connected IoT assets. Finance and Operations—often called Finance and Supply Chain Management today—runs core ERP: general ledger, accounts payable and receivable, budgeting, fixed assets, procurement, inventory, warehouse, production, and transportation. The first three apps live on the Dataverse platform and are extended with Power Platform tools; Finance and Operations runs on its own application stack and uses X++ for server-side business logic.

When people say “datasource” in the Finance and Operations world, they usually mean one of two things. On a form, a datasource is the object that points at a table or view and defines how records are fetched, joined, filtered, and displayed. In code, a Query contains QueryBuildDataSource nodes; each node represents a table or view and how it relates to other nodes. That’s the building block you join to pull exactly the rows you want, whether you’re filling a form grid, building a report, or driving a batch job.

Dataverse is the data platform behind Dynamics 365 Sales, Customer Service, and Field Service (and the rest of the Power Platform). It provides a standardized schema, rich security, business rules, plug-ins, and low-code automation. Finance and Operations has a separate SQL database optimized for ERP workloads and X++ business logic. You typically don’t connect straight to that database; instead you work through data entities, OData, the DMF framework, Electronic Reporting, or near-real-time integrations like Dual-write. Dataverse favors a common, app-agnostic data model that plays nicely with Power Apps, Power Automate, and Power BI. The F&O database is tailored to ERP tables and performance characteristics. Dual-write maps many F&O concepts into Dataverse so Sales or Field Service can interact with them, but the schemas are not the same and not every ERP table is projected.

Here’s a beginner-friendly X++ example that joins datasources to answer a warehousing scenario you might see in retail automation. Imagine you want a quick list of open picking work created today for a specific warehouse so a background job can suggest “fast pick” tasks for store-pickup orders. This new October 2025 x++ query join datasource example here anchors on WHSWorkTable, joins WHSWorkLine for item and quantity, then joins InventTable for item metadata and WMSLocation for the physical slot. It filters by warehouse, work status, work type, and a created-today window. Notice the use of relations(true) so the platform’s table relations build the join correctly, and the date window uses start-of-day and end-of-day boundaries.

class RetailWarehousePickQuery
{
    public static void main(Args _args)
    {
        const str warehouseId = 'USRT'; // change to your site/warehouse

        utcDateTime startOfDay = DateTimeUtil::newDateTime(systemDateGet(), 0);
        utcDateTime endOfDay   = DateTimeUtil::newDateTime(systemDateGet(), 86399);

        Query                   query = new Query();
        QueryRun                qr;
        QueryBuildDataSource    qWkT, qWkL, qInvent, qLoc;

        WHSWorkTable            workT;
        WHSWorkLine             workL;
        InventTable             invent;
        WMSLocation             loc;

        query.allowCrossCompany(false);

        qWkT = query.addDataSource(tableNum(WHSWorkTable));
        qWkT.addRange(fieldNum(WHSWorkTable, InventLocationId)).value(queryValue(warehouseId));
        qWkT.addRange(fieldNum(WHSWorkTable, WorkType)).value(queryValue(WHSWorkType::Pick));
        qWkT.addRange(fieldNum(WHSWorkTable, WorkStatus)).value(queryValue(WHSWorkStatus::Open));
        qWkT.addRange(fieldNum(Common, CreatedDateTime)).value(SysQuery::range(startOfDay, endOfDay));

        qWkL = qWkT.addDataSource(tableNum(WHSWorkLine));
        qWkL.relations(true);                 // join by WorkId and related keys
        qWkL.joinMode(JoinMode::InnerJoin);

        qInvent = qWkL.addDataSource(tableNum(InventTable));
        qInvent.relations(true);              // join by ItemId
        qInvent.joinMode(JoinMode::InnerJoin);

        qLoc = qWkL.addDataSource(tableNum(WMSLocation));
        qLoc.relations(true);                 // join by InventLocationId + WMSLocationId
        qLoc.joinMode(JoinMode::InnerJoin);

        qr = new QueryRun(query);

        while (qr.next())
        {
            workT  = qr.get(tableNum(WHSWorkTable));
            workL  = qr.get(tableNum(WHSWorkLine));
            invent = qr.get(tableNum(InventTable));
            loc    = qr.get(tableNum(WMSLocation));

            info(strFmt("Work %1 | Item %2 (%3) | Qty %4 | Location %5",
                workT.WorkId,
                workL.ItemId,
                invent.itemName(),
                workL.Qty,
                loc.LocationId));
        }
    }
}

A few tips that help beginners build confidence with joins in warehouse data. Filter as early as possible on the parent datasource so the engine touches fewer rows on the children. Favor relations(true) when reasonable because it keeps joins accurate as schemas evolve; addLink works too, but multi-field joins on warehouse tables can be brittle if you later tweak the structure. Be mindful with cross-company; turning it off avoids duplicate rows in multi-company environments. And remember that CreatedDateTime is stored in UTC, so your “today” range should be built deliberately if users operate across time zones.

If you’re coming from the Sales, Customer Service, or Field Service side, the mental model is similar—compose a query, define relationships, and shape the result—but the tooling differs. On Dataverse, you’d often use Power Fx, Power Automate, or plug-ins, and query with FetchXML or the Web API. In Finance and Operations, you write X++, use Query and QueryBuildDataSource, and deploy logic through classes, form datasources, SysOperation, or batch. Both worlds can collaborate: for example, Dual-write can surface key warehouse and product data in Dataverse so a Customer Service agent can see order-fulfillment context without switching apps, while X++ batch jobs keep the inventory truth up to date.

Have a Question ?

Fill out this short form, one of our Experts will contact you soon.

Call Us Today For Your Free Consultation