Table Methods in AX 2012: X++ Reference for Overrides, Kernel Helpers and Conventions
This reference lists the table methods you override or call in Dynamics AX 2012 (RTM, R2, R3), split into kernel overrides, kernel helpers and the static find/exist conventions. Each row says when the kernel calls the method and the tip that avoids the most common bug or slowdown.
| Method | Kind | When it runs | Returns | Tip |
|---|---|---|---|---|
initValue | Override | When a new record is created in a form, or when you call it in code after declaring a buffer | void | Put field defaults here, not in insert, so the user sees them before saving |
validateField | Override | When a field is changed in a form, before modifiedField | boolean | Use a switch on the field id; return checkFailed(...) to block the value |
modifiedField | Override | After a field value is accepted in a form | void | Cascade dependent fields here (for example fill a name from an account) |
validateFieldValue | Override | Field validation variant that receives field name and array index | boolean | Use for array fields; check your xRecord node to see if your kernel exposes it |
modifiedFieldValue | Override | Modified-field variant that receives field name and array index | void | Pair with validateFieldValue when overriding array field behaviour |
validateWrite | Override | On save from a form. Not called automatically by insert() or update() in code | boolean | Call it explicitly before insert or update in import code; never write to the database inside it |
validateDelete | Override | On delete from a form. Not called automatically by delete() in code | boolean | Block deletes of records still in use; call it yourself in batch code |
insert | Override | When code or a form inserts a record | void | super() performs the actual write; logic before super() can still change fields |
update | Override | When code or a form updates a selected-for-update record | void | Compare this.field with this.orig().field to react only to real changes |
delete | Override | When code or a form deletes a record | void | Delete actions run in super(); keep extra cleanup inside the same transaction |
doInsert | Kernel helper | Only when you call it | void | Writes the record without calling the overridden insert(); use for data fixes only |
doUpdate | Kernel helper | Only when you call it | void | Bypasses the overridden update(); business logic in update() is skipped |
doDelete | Kernel helper | Only when you call it | void | Bypasses the overridden delete(); business logic in delete() is skipped, so use for data fixes only |
aosValidateInsert | Override | On the AOS for every insert, from any client or code | boolean | Server-side guard that cannot be bypassed by client code |
aosValidateUpdate | Override | On the AOS for every update | boolean | Keep it light; it runs for every row |
aosValidateDelete | Override | On the AOS for every delete | boolean | Use for hard rules such as never delete posted records |
aosValidateRead | Override | On the AOS when a record is read | boolean | Very hot path; avoid queries here |
skipDataMethods | Kernel helper | Call before update_recordset, delete_from or insert_recordset | boolean | skipDataMethods(true) stops per-row calls to overridden update/delete/insert so set-based statements stay set-based |
skipDatabaseLog | Kernel helper | Call before a set-based operation | boolean | Database logging on a table forces row-by-row; skip only if audit rules allow |
skipEvents | Kernel helper | Call before a set-based operation | boolean | Alerts and events also force row-by-row processing |
skipDeleteActions | Kernel helper | Call before delete_from | boolean | Skips delete actions; you then own referential cleanup |
skipAosValidation | Kernel helper | Call before a write | boolean | Skips aosValidate methods; data migration only |
orig | Kernel helper | Any time after a record is selected | Common (the record as last read) | Use in update() to detect changed fields |
reread | Kernel helper | When you call it | void | Reloads the buffer from the database, for example after another process changed it |
data | Kernel helper | When you call it | Common | Copies field values from another buffer of the same table: target.data(source) |
clear | Kernel helper | When you call it | void | Empties the buffer before reuse in a loop |
isFormDataSource | Kernel helper | When you call it | boolean | Branch logic that should run only when the record is bound to a form |
caption | Override | When a form shows the record caption | str | Return the key and name so the form title is meaningful |
postLoad | Override | After a record is fetched from the database | void | Runs for every fetched row; avoid database calls here |
renamePrimaryKey | Kernel helper | From the Rename function or your code | void | Cascades a key change to related tables; slow on large data |
toolTipRecord | Override | When the client shows a tooltip for the record | str | Keep it to a short description |
find | Static convention | Called by your code: Table::find(key, forUpdate) | The table buffer | select firstonly with an optional forUpdate parameter; not a kernel method |
exist | Static convention | Called by your code: Table::exist(key) | boolean | select firstonly RecId only, for speed |
checkExist | Static convention | Called by your code before using a key | boolean | Wraps exist() and adds checkFailed with txtNotExist() |
txtNotExist | Static convention | Called by checkExist | str (label text) | Return a label such as "Record %1 does not exist" |
Find table methods in the AOT under Data Dictionary > Tables > your table > Methods. Right-click Methods > Override method lists the xRecord methods the kernel lets you override. The write() method belongs to the form data source, not the table. find, exist, checkExist and txtNotExist are Microsoft coding conventions you add as static methods, not kernel methods.
Planning to move AX 2012 code to D365?
Send us a list of your overridden table methods and we will flag which ones need rework as event handlers or extensions.
Optional. The tool and every export work without this. No spam.
How to use it
Search for the method you are about to override or the behaviour you see. The Kind column tells you whether the kernel calls the method (Override), whether you call it yourself (Kernel helper), or whether it is a convention you write (Static convention). The When it runs column is the important one: validateWrite and validateDelete run on form saves, not on insert() or update() from code, which is why import jobs so often write invalid data. Export the table and add your own team rules as extra rows.
- Defaults: initValue
- Field rules: validateField then modifiedField
- Record rules: validateWrite, validateDelete
- Hard server rules: aosValidateInsert, aosValidateUpdate, aosValidateDelete
Where this lives in AX 2012
Open the AOT (Ctrl+D), expand Data Dictionary > Tables, pick the table and expand Methods. Right-click Methods > Override method to add an xRecord override; right-click Methods > New method for static find and exist. The X++ editor opens the method; super() calls the kernel behaviour. In AX 2012 the code is compiled to p-code and, for server code, also to CIL, so run a full CIL compile after changes that batch or services use.
Worked example: find and exist on a custom table
For a table XyzMachineTable with unique index on MachineId, write: static XyzMachineTable find(XyzMachineId _id, boolean _forUpdate = false) { XyzMachineTable rec; rec.selectForUpdate(_forUpdate); select firstonly rec where rec.MachineId == _id; return rec; } and static boolean exist(XyzMachineId _id) { return _id && (select firstonly RecId from XyzMachineTable where XyzMachineTable.MachineId == _id).RecId != 0; }. Add checkExist that calls exist and returns checkFailed(strFmt(XyzMachineTable::txtNotExist(), _id)) when missing.
Gotchas: set-based operations
insert_recordset, update_recordset and delete_from fall back to row-by-row processing when the table overrides insert, update or delete, has database logging or alerts enabled, or has delete actions (for delete_from). Call skipDataMethods(true), skipDatabaseLog(true), skipEvents(true) or skipDeleteActions(true) on the buffer only when skipping that logic is correct. Remember that doInsert, doUpdate and doDelete bypass your overrides entirely, and that validateWrite is never called by the kernel during code inserts.
Frequently Asked Questions
What are the main table methods in AX 2012?
The common overrides are initValue, validateField, modifiedField, validateWrite, validateDelete, insert, update, delete and the aosValidate methods. Kernel helpers include doInsert, doUpdate, doDelete, orig, reread, data, clear and the skip methods. find and exist are static conventions you write yourself.
Is validateWrite called when I call insert() in X++?
No. validateWrite runs when a form saves a record. In code you must call it yourself: if (rec.validateWrite()) rec.insert(); The same applies to validateDelete before delete(). aosValidateInsert and the other aosValidate methods do run on the server for every write.
What is the difference between insert and doInsert in AX 2012?
insert() calls your overridden insert method, which normally calls super() to write the row. doInsert() writes the row directly without calling your override, so any logic in insert() is skipped. Use doInsert only for controlled data fixes where that logic must not run.
Why is my update_recordset slow?
It is probably running row by row. AX falls back when the table overrides update(), has database logging or alerts, or other per-row logic. Call skipDataMethods(true) and the other skip methods on the buffer before the statement if bypassing that logic is acceptable, then test the row count.
If you want developers and support staff to ask questions about your AX 2012 data and code base in plain English on your own servers, we can set up that private AI layer.
Related Tools
Dynamics AX 2012 SQL Reporting Query Generator (DATAAREAID, PARTITION, Enums)
Builds T-SQL for an AX 2012 R2/R3 business database: sales lines with status labels and customer names, filtered by company and partition, plus table and field IDs from SQLDICTIONARY.
Microsoft DynamicsDynamics AX 2012 AIF Inbound Sales Order Message Generator (File System Adapter)
Fill in customer, PO reference, item, quantity, site and warehouse to get a ready-to-drop AIF envelope for SalesOrderService create, with the AIF batch tasks and troubleshooting steps.
Microsoft DynamicsDynamics AX Customization Inventory Worksheet
Editable inventory of AX customizations with layer, disposition and rework estimate per object, totaled for upgrade planning.
Microsoft DynamicsAX 2012 Customization Remediation Effort Calculator
Converts counts of overlayered objects, custom reports, integrations and ISV modules into hours, cost and calendar weeks for D365 Finance and Operations remediation.
More Microsoft Dynamics tools
See all- AX 2012 to D365 Finance and Operations Upgrade Effort Estimator
- Dynamics AX 2012 Retirement Project Charter Template
- AX 2012 to D365 Data Entity Mapping Worksheet
- Dynamics AX 2012 R3 Safety Stock Journal Minimum Calculator
- D365 F&O Manufacturing Data Entities Reference
- D365 F&O OData URL Builder
- D365 Production Order Status Reference
- D365 Data Management Import Worksheet Template
- D365 Batch Job Checklist
Keep exploring
Free tools
- AX 2012 Table to D365 Data Entity ReferenceLook up the D365 F&O data entity and OData collection that corresponds to a Dynamics AX 2012 table when planning data migration.
- Dynamics AX Customization Inventory WorksheetEditable inventory of AX customizations with layer, disposition and rework estimate per object, totaled for upgrade planning.
- Dynamics AX 2012 AI Assistant Sizing and Value CalculatorSize the GPUs, retrieval index and monthly value of a private AI assistant for AX 2012 from your user count and question volume.
ERP fixes and how-tos
- Adding a Private AI Layer to Dynamics AX 2012 On-PremAdd AI to Dynamics AX 2012 on-prem without moving data: SQL replica, AIF services, retrieval index, local LLM, mirrored AX roles, approved write-back.
- Planning an AX 2012 to Dynamics 365 Finance and Operations upgradeHow an AX 2012 to Dynamics 365 Finance and Operations upgrade actually runs: LCS upgrade project, code upgrade of customizations, and data migration, with the main risks.
- Fixing "The CIL object was not found" in Dynamics AX 2012AX 2012 throws CIL object not found after code changes. What CIL generation actually does, why incremental CIL misses it, and the full rebuild fix.
Integrations
- How to add AI agents to Microsoft Dynamics AX 2012How to add AI agents to Dynamics AX 2012 using AIF services, SQL read paths and approval gates, without a forced move to Dynamics 365 first.
- How to use ChatGPT with Microsoft Dynamics AX 2012How to use ChatGPT with Dynamics AX 2012: exports versus live access, custom GPT actions over AIF, enterprise data controls and when to go private.