crossCompany in X++: The Query That Mixes Legal Entities
A select in X++ is scoped to the company the session is in. CustTable in USMF does not return USSI customers, because the kernel adds the current DataAreaId. The crossCompany keyword removes that filter. It does not remove security. Microsoft's select-statement reference is specific: the keyword returns data for all companies the user is authorized to read. A batch account that can open every legal entity will, and the report will look correct while it mixes them.
Constrain the companies in the statement
Pass a container. The query is then limited to that list, and still only to companies the user may read. The container can be a variable or an expression.
CustTable custTable;
container companies = ['USMF', 'USSI'];
while select crossCompany: companies custTable
order by custTable.DataAreaId
{
// custTable.DataAreaId tells you which company this row came from
}
An unconstrained while select crossCompany custTable is the version that shows up in incidents. The author tested it in a one-company dev box, where "all companies" and "this company" are the same set. In production the service account can read twenty legal entities, and a customer balance from the wrong one lands on a statement.
Anything you display or export from that loop has to carry DataAreaId. A grid of account numbers with no company column is how someone pays the USSI invoice against the USMF customer of the same number.
Reading across companies does not switch the session
crossCompany changes which rows a select can see. It does not change curext(), and it does not retarget number sequences, default dimensions, or inserts. Read a customer from USSI and then call SalesTable.insert() and the order is created in the company the session started in.
Writes that must land in another company go inside changeCompany, which switches the session for the block:
changeCompany('USSI')
{
// curext() is USSI here, including number sequences and inserts
}
The same split exists on data entities. When PrimaryCompanyContext is set, X++ reads are filtered to the current company unless the query asks for cross-company data. OData reads are not filtered. The caller has to send dataAreaId itself. An integration that pages an entity with no company filter is a cross-company export whether or not anyone typed the keyword. That is also why a throttled OData client can look "random": it is walking every legal entity. The request limits in OData throttling assume you meant to read that much.
Query objects follow the same rule. allowCrossCompany(true) opens the query, and addCompanyRange puts the container back. A form or a report that sets the flag and never adds a range has the same bug as the unconstrained select.
What to check before it ships
The user on the batch job is the real scope. crossCompany cannot see a company that user cannot open, and it will see every company that user can. A service account granted System user in every legal entity is not a narrow integration account. Pair the keyword with an explicit company list taken from the job parameters, and keep inserts inside changeCompany for the company you mean to post to. Security roles still decide who may open a company at all; they are covered in roles, duties, and privileges. The keyword does not add a second check on top of that.
Keep reading
Budget Control in Finance 10.0.49: Closed Periods, Reservations, and Broken Tracking
The budgeting features in Dynamics 365 Finance 10.0.49 — accounting-date advancement, reservation posting, encumbrance reporting, and a diagnostic for corrupt budget tracking.
Bank and Cash in Finance 10.0.49: Delayed Settlement, Match Preview, and Bridge Selection
What Dynamics 365 Finance 10.0.49 changes in payment journals and bank reconciliation, which pieces are still preview, and which bank behaviors you can no longer disable.
D365 F&O 10.0.49: What to Regression-Test Before the October Auto-Update
Finance and Supply Chain 10.0.49 (build 10.0.2790) is self-update in September 2026 and auto-update in October. Here is the feature-state triage that actually matters.
Agentic ERP in September 2026: What Is Available, in Preview, and Still a Date
A precise reading of Microsoft's 23 September 2026 Dynamics 365 ERP announcement, the 10.0.49 previews behind it, and the financial-journal dates that are not this fall.
Electronic Reporting in Finance 10.0.49: GS1 Barcodes, DIV and MOD, and Copy Counts
What Dynamics 365 Finance 10.0.49 changes in Electronic Reporting without a feature debate — barcode formats, integer formulas, print copies — and which ER behaviors are now mandatory.
France E-Invoicing and E-Reporting in D365 Finance: What 10.0.49 Actually Files
How Dynamics 365 Finance splits French domestic B2B e-invoicing from e-reporting, which build carries it, and what SIREN, SIRET, and establishment setup must be true before you transmit.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.