GraphQL Extensions /businessnxtapi/extensions section GraphQL schema for data model extensions. 2026-02-11T13:24:48+02:00 # GraphQL Extensions GraphQL schema for data model extensions. > [!WARNING] > This feature is currently in preview. Although the implementation is complete and the schema extensions are available for everyone, the access to data model extensions is restricted to selected customers. If you are not one of these customers, you cannot create data model extensions. You can still use all the API extensions available in the schema for generically querying the model, but only for the code data model. The GraphQL schema is dynamically built from the core data model. It exposes tables, columns, relations, processings, reports the way they are defined in the core model. BNXT supports extending the model with new tables, columns, relations, and others. These data model extensions (DMEs for short) are accessible through GraphQL just like the core model. However, these extensions are not available the same way the core model is. GraphQL features a single schema, and that cannot expose all customer-specific extensions in a strongly-type named. For this reason, generic extensions are available everywhere DMEs are possible. > [!TIP] > Although these generic extensions to the schema are designed for DMEs, it is possible to also query the core model using them. However, we advice that you only use them for DMEs. ## Getting started with extensions Extensions are referenced using their name identifiers, and not model numbers: - columns and tables by their name - relations by their name and where necessary to avoid ambiguity, also by their source and target table name A few examples are provided here to get you started. ```graphql query read_order($cid:Int!) { useCompany(no:$cid) { order(first:5) { items { orderNo orderDate extensions { customerNo : integerValue createdAt : dateValue(name: "createdDate") } } } } } ``` The `extensions` field is available on all tables, and it exposes all extension columns defined for that table. You can query the extension columns by their name using the appropriate typed field. There are two ways to query a field: - using an alias, which is interpreted as the name of the extension column, such as in `customerNo : integerValue` - using the `name` argument to specify the name of the extension column, such as in `createdAt : dateValue(name: "createdDate")` When both an alias and the `name` argument are used, the `name` argument takes precedence and the alias is not considered for identifying the company. The possible field names for extension columns are: - `integerValue` - `decimalValue` - `stringValue` - `booleanValue` - `dateValue` - `timeValue` - `timestampValue` Each column has a domain with a specific data type. Data types can be integer, decimal, boolean, string, date, timestamp. If the requested data type (such as `integer` for `integerValue`) does not match the domain data type of the extension column, the value `null` is returned. The following example utilizes a relation extension to query related data from an extension table: ```graphql query read_order($cid:Int!) { useCompany(no:$cid) { order(first:5) { items { orderNo orderDate extensions { customerNo : integerValue createdAt : dateValue(name: "createdDate") } joinup_Associate_via_Customer { name extensions { joinup(relation: "Country") { name : stringValue } } } } } } } ``` The last example here shows how to query a table, use filters and sorting, and also do joins using the generic extensions schema: ```graphql query read_table($cid:Int!) { useCompany(no:$cid) { table( name : "order", first: 5, filter : { joindown : { relation : { name : "Order", from : "OrderLine" } _some : { joinup :{ relation : { name : "Product" }, column : "Description", stringValue : { _eq : "Product 103" } } } } } orderBy : [ {column : "customerNo", order : DESC}, {column : "orderDate", order : ASC}, {column : "orderNo"} ]) { items { orderNo : integerValue customerNo : integerValue address : stringValue (name : "addressLine1") orderDate : dateValue createdDate : dateValue createdTime : timeValue createdTimestamp : timestampValue totalDiscountPercent : decimalValue editStatus : integerValue joindown(relation : "Order", from : "OrderLine") { items { orderNo : integerValue lineNo : integerValue joinup(relation : "Product") { description : stringValue } } } joinup(relation : "Customer") { name : stringValue joinup(relation : "Country") { name : stringValue joinup(relation : "Language") { name : stringValue } } } } } } } ``` This query uses the core model entirely and is the equivalent of the following: ```graphql query read_order($cid:Int!) { useCompany(no:$cid) { order( first: 5, filter : { joindown_OrderLine_via_Order : { _some : { joinup_Product : { description : { _eq : "Product 103" } } } } } orderBy : [ {customerNo : DESC}, {orderDate : ASC}, {orderNo : ASC} ]) { items { orderNo customerNo joindown_OrderLine_via_Order { items { orderNo lineNo joinup_Product { description } } } joinup_Associate_via_Customer { name joinup_Country { name joinup_Language { name } } } } } } } ``` Read extensions /businessnxtapi/extensions/readextensions page GraphQL API documentation on schema read generic extensions. 2026-02-11T13:24:48+02:00 # Read extensions GraphQL API documentation on schema read generic extensions. BNXT GraphQL schema extensions for data model extensions reads are documented in this section. There is no difference between querying the core model or a model extension. However, it is recommended that you use the extensions schema for DMEs only. ## Querying an extension column To query an extension column, there are two options: - use an alias to indicate the actual column name (`customerNo : integerValue`), or - use the `name` argument to indicate the column name (`cno : integerValue(name : "customerNo")`) The case of the name value is irrelevant. But if both an alias and the `name` argument are present, the `name` argument is used to identify the column. Each table type has a special field along the table column fields used for querying the extension columns. This field is called `extensions`. This field includes the following subfields: - `integerValue` - `decimalValue` - `stringValue` - `booleanValue` - `dateValue` - `timeValue` - `timestampValue` Each column has a domain with a specific data type. Data types can be integer, decimal, boolean, string, date, timestamp. If the requested data type (such as `integer` for `integerValue`) does not match the domain data type of the extension column, the value `null` is returned. In the following example, `extensions` is used to fetch the value of the `customerNo` and `createdDate` fields from the `Order` table. ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order(first : 1) { items { orderNo orderDate extensions { customerNo : integerValue createdAt : dateValue(name: "createdDate") } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 1, "orderDate": 20210212, "extensions": { "customerNo": 10002, "createdAt": "2020-05-11" } } ] } } } } ``` ## Joinup extensions Data model extensions can include relations. These can be one-to-one (called `joinup`) or one-to-many (called `joindown`). Custom joinup relations can be querying by specifying: - the relation name (identifier) - optionally the source and target table name, if the relation name is ambiguous The following example shows up-joining from the Order table to Associate, to Country, and finally to Language. All the joins are done using the extension `joinup` field. ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order(first : 1) { items { orderNo extensions { joinup(relation : "Customer") { name : stringValue joinup(relation: "Country") { name : stringValue joinup(relation: "Language") { name : stringValue } } } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 1, "extensions": { "joinup": { "name": "Access Vital AS", "joinup": { "name": "Norway", "joinup": { "name": "Norsk" } } } } } ] } } } } ``` ## Joindown extensions The `joindown` relations are similar to `joinup`, except that their GraphQL type is a connection type. The following example shows fetching the order lines for an order using the `extensions` field. ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order(first : 1) { items { orderNo orderDate extensions { joindown(relation: "Order", from: "OrderLine") { items { orderNo : integerValue lineNo : integerValue productNo : stringValue joinup(relation: "Product") { name : stringValue(name: "description") } } } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 1, "orderDate": 20210212, "extensions": { "joindown": { "items": [ { "orderNo": 1, "lineNo": 1, "productNo": "312", "joinup": { "name": "Callaway Big Bertha 4-PW grafitt Herre" } }, { "orderNo": 1, "lineNo": 2, "productNo": "313", "joinup": { "name": "Callaway Big Bertha Fusion jern" } } ] } } } ] } } } } ``` ## Filter extensions Extension columns can be used in filters too. However, arguments are defined by input types and these cannot have arguments themselves. Therefore, for all input types, the schema is sligtly different. For columns, you need to specify the column name and the value expression. The following examples shows how to fetch orders that belong to the customer with number 10010: ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order( first : 3, filter : { extensions : { column : "customerNo", integerValue : { _eq : 10010 } } } ) { items { orderNo customerNo } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 86, "customerNo": 10010 }, { "orderNo": 97, "customerNo": 10010 }, { "orderNo": 136, "customerNo": 10010 } ] } } } } ``` ## Filter joinup extensions It is possible to filter on the value of columns from joined tables. For one-to-one relations, this is done using the `joinup` input field. In the previous example, we queried orders for a customer indicated by its number. However, we can do the same using the name of the customer, from the Associate table. This is possible with a filter join. For extensions, this requires the `extensions` and the `joinup` fields: ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order( first : 3, filter : { extensions : { joinup : { relation : { name : "Customer", to : "Associate" }, column : "Name", stringValue : { _eq : "American Designers" } } } } ) { items { orderNo customerNo } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 86, "customerNo": 10010 }, { "orderNo": 97, "customerNo": 10010 }, { "orderNo": 136, "customerNo": 10010 } ] } } } } ``` In this example, notice the following: - The input field `relation` is used to indicate the relation to join through. It contains fields for the relation name as well as optionally for the `from` and `to` table names. When the `from` argument is missing, it's implied as the name of the table from which the join is defined. - The `column` field is used to indicate the name of the column in the target table (`Associate` in this case) to filter on. - The actual filter expression is provided in the field corresponding to the data type of the column (`stringValue` in this case). ## Filter joindown extensions It's possible to use joins to filter on one-to-multiple relations too. This is possible using the equivalent `joindown` input field. For instance, in the following example we query orders that have at least one order line for product number `"103"`: ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order( first : 1, filter : { extensions : { joindown : { relation : { name : "Order", from : "OrderLine" }, _some : { column : "productNo", stringValue : { _eq : "103" } } } } } ) { items { orderNo joindown_OrderLine_via_Order { items { lineNo productNo } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 4, "joindown_OrderLine_via_Order": { "items": [ { "lineNo": 1, "productNo": "311" }, { "lineNo": 2, "productNo": "311" }, { "lineNo": 3, "productNo": "1001" }, { "lineNo": 4, "productNo": "103" } ] } } ] } } } } ``` We can expand the example, to perform the same query but using the name of the product, as defined in the `Product` table, instead of its number: ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order( first : 1, filter : { extensions : { joindown : { relation : { name : "Order", from : "OrderLine" }, _some : { joinup : { relation : { name : "Product" }, column : "Description", stringValue : { _eq : "Product 103" } } } } } } ) { items { orderNo joindown_OrderLine_via_Order { items { lineNo productNo joinup_Product { description } } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 4, "joindown_OrderLine_via_Order": { "items": [ { "lineNo": 1, "productNo": "311", "joinup_Product": { "description": "Callaway Big Bertha Fusion FT 3 Driver" } }, { "lineNo": 2, "productNo": "311", "joinup_Product": { "description": "Callaway Big Bertha Fusion FT 3 Driver" } }, { "lineNo": 3, "productNo": "1001", "joinup_Product": { "description": "Olyo MS 0703 Carbon Crown Rescue Wood" } }, { "lineNo": 4, "productNo": "103", "joinup_Product": { "description": "Product 103" } } ] } } ] } } } } ``` ## Ordering extensions Extension columns can be used to define the sorting order too. In this case, you need to specify the column name and, optionally, the order direction. If the order direction is not specified, ascending order is used by default. The following example shows how to orders by their `customerNo` extension column in descending order: ```graphql { title = "Query" } query read_order($cid:Int!) { useCompany(no:$cid) { order( first : 3, orderBy : [ { extensions : { column : "customerNo", order : DESC } } ] ) { items { orderNo customerNo } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order": { "items": [ { "orderNo": 47, "customerNo": 49999 }, { "orderNo": 356, "customerNo": 30018 }, { "orderNo": 358, "customerNo": 30012 } ] } } } } ``` ## Grouping extensions To group by column extensions, use the `extensions` field. You need to specify the column name and, optionally, the grouping order, which can be either `DEFAULT` or `ROLLUP`. If the grouping order is not specified, `DEFAULT` is used. The following example shows fetching data from the general ledger transactions table, on account 3000 and year 2020, grouping the results by the `AccountNo` column with `ROLLUP` grouping, and the period, also with the `ROLLUP` grouping: ```graphql { title = "Query" } query read_gla_transactions_grouped($cid : Int) { useCompany(no : $cid) { generalLedgerTransaction( filter : { _and: [ {accountNo : {_gte : 3000}}, {year : {_gte : 2020}} ]}, groupBy: [ { extensions : { column : "AccountNo", grouping : ROLLUP } }, {period : ROLLUP} ]) { items { accountNo period aggregates { sum { postedAmountDomestic } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "generalLedgerTransaction": { "items": [ { "accountNo": 3000, "period": 4, "aggregates": { "sum": { "postedAmountDomestic": -100 } } }, { "accountNo": 3000, "period": 12, "aggregates": { "sum": { "postedAmountDomestic": -4950 } } }, { "accountNo": 3000, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": -5050 } } }, { "accountNo": 4000, "period": 12, "aggregates": { "sum": { "postedAmountDomestic": 450 } } }, { "accountNo": 4000, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 450 } } }, { "accountNo": 4410, "period": 4, "aggregates": { "sum": { "postedAmountDomestic": 400 } } }, { "accountNo": 4410, "period": 12, "aggregates": { "sum": { "postedAmountDomestic": 13035 } } }, { "accountNo": 4410, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 13435 } } }, { "accountNo": 0, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 8835 } } } ] } } } } ``` ## Having clause extensions The `having` clause expressions are very similar to the filter expressions. You need to specify the column name and its value expression. In the following example, we run the same query as above, except that a having clause is used to filter and retain only the groups where the sum of the `postedAmountDomestic` is greater than 100: ```graphql { title = "Query" } query read_gla_transactions_grouped($cid : Int) { useCompany(no : $cid) { generalLedgerTransaction( filter : { _and: [ {accountNo : {_gte : 3000}}, {year : {_gte : 2020}} ]}, groupBy: [ { extensions : { column : "AccountNo", grouping : ROLLUP } }, {period : ROLLUP} ], having : { _sum : { extensions : { column : "postedAmountDomestic" decimalValue : { _gt : 100 } } } }) { items { accountNo period aggregates { sum { postedAmountDomestic } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "generalLedgerTransaction": { "items": [ { "accountNo": 4000, "period": 12, "aggregates": { "sum": { "postedAmountDomestic": 450 } } }, { "accountNo": 4000, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 450 } } }, { "accountNo": 4410, "period": 4, "aggregates": { "sum": { "postedAmountDomestic": 400 } } }, { "accountNo": 4410, "period": 12, "aggregates": { "sum": { "postedAmountDomestic": 13035 } } }, { "accountNo": 4410, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 13435 } } }, { "accountNo": 0, "period": 0, "aggregates": { "sum": { "postedAmountDomestic": 8835 } } } ] } } } } ``` ## Aggregate extensions Previously, we have see how to use extension columns in grouping and having clauses. These are connection arguments. But the extensions columns can be used in the projected aggregated results too. The syntax is similar to that of regular columns. In the following example, the sum of the `postedAmountDomestic` is fetched using the schema extensions: ```graphql { title = "Query" } query read_gla_transactions_grouped($cid : Int) { useCompany(no : $cid) { generalLedgerTransaction( filter : { _and: [ {accountNo : {_gte : 3000}}, {year : {_gte : 2020}} ]}, groupBy: [ { extensions : { column : "AccountNo", grouping : ROLLUP } }, {period : ROLLUP} ], having : { _sum : { extensions : { column : "postedAmountDomestic" decimalValue : { _gt : 100 } } } }) { items { accountNo period aggregates { sum { extensions { postedAmountDomestic : decimalValue } } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "generalLedgerTransaction": { "items": [ { "accountNo": 4000, "period": 12, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 450 } } } }, { "accountNo": 4000, "period": 0, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 450 } } } }, { "accountNo": 4410, "period": 4, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 400 } } } }, { "accountNo": 4410, "period": 12, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 13035 } } } }, { "accountNo": 4410, "period": 0, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 13435 } } } }, { "accountNo": 0, "period": 0, "aggregates": { "sum": { "extensions": { "postedAmountDomestic": 8835 } } } } ] } } } } ``` ## Table extensions The data model extensions allows adding new tables, as well as relations between these tables and existing (core model) tables. To query an extension table, you need to use the generic `table` connection. This is defined by a connection type like all the other connection fields in the schema, with the same arguments. However, instead of defining name columns, it uses all the extension features shown above. The key difference is that the `table` connection being an extension itself, it does not define inner fields called `extensions`, like we have seen above. The following example shows how to query a table using the `table` connection. ```graphql { title = "Query" } query read_table($cid:Int!) { useCompany(no:$cid) { table( name : "order", first: 3, filter : { joindown : { relation : { name : "Order", from : "OrderLine" } _some : { joinup :{ relation : { name : "Product" }, column : "Description", stringValue : { _eq : "Product 103" } } } } } orderBy : [ {column : "customerNo", order : DESC}, {column : "orderDate", order : ASC}, {column : "orderNo"} ]) { items { orderNo : integerValue customerNo : integerValue address : stringValue (name : "addressLine1") orderDate : dateValue createdDate : dateValue createdTime : timeValue createdTimestamp : timestampValue totalDiscountPercent : decimalValue editStatus : integerValue joindown(relation : "Order", from : "OrderLine") { items { orderNo : integerValue lineNo : integerValue joinup(relation : "Product") { description : stringValue } } } joinup(relation : "Customer") { name : stringValue joinup(relation : "Country") { name : stringValue joinup(relation : "Language") { name : stringValue } } } } } } } ``` Write extensions /businessnxtapi/extensions/writeextensions page GraphQL API documentation on schema write generic extensions. 2026-02-11T13:24:48+02:00 # Write extensions GraphQL API documentation on schema write generic extensions. BNXT GraphQL schema extensions for data model extensions writes are documented in this section. There is no difference between performing mutation operations on the core model or a model extension. However, it is recommended that you use the extensions schema for DMEs only. ## Writing extension columns When entering input values for extension columns, you must specify the column name and its value. For this, a special type called `InputValueExtension` is used. This type has the following fields: | Field | Type | Description | | ----- | ---- | ----------- | | column | String! | Name of the column | | integerValue | Int | An integer value | | stringValue | String | A string value | | decimalValue | Decimal | A decimal value | | booleanValue | Boolean | A boolean value | | dateValue | Date | A date value | | timeValue | String | A time value | | timestampValue | DateTime | A timestamp value | The `column` field is mandatory and specifies the name of the extension column. The other fields are optional and represent the value to be set for the column. Only one of these value fields should be provided per input. If more than one is provided, an error will be returned. Here is an example of how to create an order and line both using extensions: ```graphql { title = "Query" } mutation create_order($cid :Int!) { useCompany(no : $cid) { order_create(values : [ { extensions : [ { column : "customerNo", integerValue : 10010 } ] orderLines : [ { productNo : "103", extensions : [ { column : "quantity", integerValue : 2 } ] } ] } ]) { affectedRows items { orderNo customerNo joindown_OrderLine_via_Order { items { orderNo lineNo productNo quantity } } } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order_create": { "affectedRows": 1, "items": [ { "orderNo": 2913, "customerNo": 10010, "joindown_OrderLine_via_Order": { "items": [ { "orderNo": 2913, "lineNo": 1, "productNo": "103", "quantity": 2 } ] } } ] } } } } ``` ## Updating extension columns The syntax for updating extension columns is similar to that of writing them. You need to specify the column name and the new value using the `InputValueExtension` type. Filters are written in the same way as for reads. Here is an example of how to update an order using extensions syntax: ```graphql { title = "Query" } mutation update_order($cid :Int!, $ono : Int!) { useCompany(no : $cid) { order_update( filters : [ { extensions : { column : "orderNo", integerValue : {_eq : $ono} } } ] values : [ { extensions : [ { column : "Name", stringValue : "Lars Olafson" } ] } ] ) { affectedRows items { orderNo name } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "order_update": { "affectedRows": 1, "items": [ { "orderNo": 2913, "name": "Lars Olafson" } ] } } } } ``` ## Deleting with filter extensions To delete data from an existing table using fileters on extension columns, you can define filters in the same way as for updating values. The following example shows how to delete records from the order line and order tables using filter extensions for the `orderNo` column: ```graphql { title = "Query" } mutation delete_order($cid : Int!, $ono : Int!) { useCompany(no : $cid) { orderLine_delete(filter : { extensions : { column : "orderNo", integerValue : {_eq : $ono} } }) { affectedRows } order_delete(filter : { extensions : { column : "orderNo", integerValue : {_eq : $ono} } }) { affectedRows } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "orderLine_delete": { "affectedRows": 1 }, "order_delete": { "affectedRows": 1 } } } } ``` ## Writing extension tables In order to write table to an exentension table, you need to use the `table_create` field. This is similar to existing table create fields, such as `order_create` or `batch_create`. However, in this case, the fields called `extensions` are missing from the schema. A mutation to create a new order may look like this: ```graphql { title = "Query" } mutation create_orders($cid :Int!) { useCompany(no : $cid) { table_create( name : "order", values : [ [ { column : "customerNo", integerValue : 10010 }, { column : "orderType", integerValue : 6 } ], [ { column : "customerNo", integerValue : 10002 }, { column : "orderType", stringValue : 1 } ] ]) { affectedRows items { orderNo : integerValue customerNo : integerValue orderType : integerValue } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "table_create": { "affectedRows": 2, "items": [ { "orderNo": 2913, "customerNo": 10010, "orderType": 6, }, { "orderNo": 2914, "customerNo": 10002, "orderType": 1, } ] } } } } ``` ## Updating extension tables In order to update records in an extension table, you need to use the `table_update` field. This is similar to existing table update fields, such as `order_update` or `batch_update`. However, in this case, the fields called `extensions` are missing from the schema. In the following examples, two orders are updated with a single request. One filter and one update value is specified for each order. ```graphql { title = "Query" } mutation update_order($cid :Int!, $ono1 : Int!, $ono2 : Int!, $cn : String!, $val1 : String!, $val2 : String!) { useCompany(no : $cid) { table_update( name : "order", filters : [ { column : "orderNo", integerValue : {_eq : $ono1} }, { column : "orderNo", integerValue : {_eq : $ono2} } ] values : [ { column : "Name", stringValue : "Lars Olafson" }, { column : "Name", stringValue : "Olaf Larson" } ] ) { affectedRows items { orderNo : integerValue name : stringValue } } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "table_update": { "affectedRows": 2, "items": [ { "orderNo": 2913, "name": "Lars Olafson" }, { "orderNo": 2914, "name": "Olaf Larson" } ] } } } } ``` ## Deleting extension tables The operation of deleting records from extension tables is done using the `table_delete` field. This is similar to existing table delete fields, such as `order_delete` or `batch_delete`. Again, as in the previous cases, the fields called `extensions` are missing from the schema. Here is an example of deleting two orders from the `Order` table: ```graphql { title = "Query" } mutation delete_order($cid : Int!, $ono1 : Int!, $ono2 : Int!) { useCompany(no : $cid) { table_delete( name : "order", filter : { column : "orderNo", integerValue : {_in : [$ono1, $ono2]} } ) { affectedRows } } } ``` ```json { title = "Result" } { "data": { "useCompany": { "table_delete": { "affectedRows": 2 } } } } ``` DME /businessnxtapi/extensions/dmes page GraphQL API documentation on data model extensions. 2026-02-11T13:24:48+02:00 # DME GraphQL API documentation on data model extensions. Data model extension contributions are created using the [Business NXT DME Admin](https://dme.business.visma.net/) tool. This tools allows you to: - Create new contributions defining new tables, columns, relations, indexes and more. - Import an existing contribution. - Apply a contribution to a customer (which means it is applied to all the companies of that customer). All data model extensions can be accessed through the GraphQL API using the GraphQL extensions schema. There are several things to keep in mind when working with DMEs in GraphQL: - Tables, columns, and relations are referenced by their indentifier (and not by model numbers). - Identifiers specified as strings (such as in `column : "myExtColumn"`, or `name : "myExtTable"`) are case-insensitive. - The actual identifier of a table, column, or relation is composed from the contribution short name and the entities identifier. For instance, if a new table has the identifier `myExtTable` and the contribution short name is `MyDme`, then the actual table identifier is `MyDme_myExtTable`. The following snippet shows an example: ```graphql { title = "Query" } query read_dme_table($cid : Int) { useCompany(no: $cid) { table(name : "mydme_myExtTable") { items { MyDme_pk : integerValue MyDme_description : stringValue MyDme_createdTimestamp : timestampValue } } } } ``` If you do not want to have fields prefixed with the contribution short name in the result JSON, you can use aliases without the prefix but specify the full column identifier in the optional name argument, as shown in the following snippet: ```graphql { title = "Query" } query read_dme_table($cid : Int) { useCompany(no: $cid) { table(name : "mydme_myexttable") { items { pk : integerValue(name : "MyDme_pk") description : stringValue(name : "MyDme_description") createdTimestamp : timestampValue(name : "MyDme_createdTimestamp") } } } } ``` Note that the casing of the identifiers in the previous examples varies to demonstrate that the identifiers are case-insensitive. For input types (such as in `filters` or `values` arguments) the column names and values are specified with separate fields, as previously described. Here is an example: ```graphql { title = "Query" } mutation create_reviews($cid :Int!, $pno : String!, $r1 : Int!, $r2 : Int!) { useCompany(no : $cid) { table_update( name : "MyDme_ProductReview", filters : [ { _and : [ { column : "MyDme_ProductNo", stringValue : {_eq : $pno} }, { column : "MyDme_ReviewNo", integerValue : {_eq : $r1} } ] } ], values : [ [ { column : "MyDme_Description", stringValue : "A good product!" } ] ]) { affectedRows items { MyDme_ProductNo : stringValue MyDme_ReviewNo : integerValue MyDme_Description : stringValue } } } } ```