# ARX.SDK types (SQL Server)

Every public type of ARX.SDK and ARX.SDK.SQL, by purpose (the less common ones last, under Other public types). Members are listed with their parameters; interop overloads that take an ADO.NET `IDbConnection` are left out: application code passes an `ArxTransaction`.

## Services and connections

The service that talks to the database, and the connection, transaction and batch scope types that group calls.

### ArxMsSqlDbService

class in `ARX.SDK.SQL.Services`, package `ARX.SDK.SQL`.

```csharp
public class ArxMsSqlDbService
```

The SQL Server service: Create, Update, Delete, Retrieve, RetrieveMultiple and Execute against one database. Give it the connection string and, usually, the application's schema catalog. It holds no connection (each call takes one from the pool), so one instance serves the whole application.

Constructors:

- `new ArxMsSqlDbService(string connectionString)`: A service with no schema catalog: before a call, it reads from the database what the call needs to know about each table (its id column, keys and column types), so simple CRUD works with only a connection string. That read costs a round trip per call unless `RememberResolvedTables` keeps it; a table with no usable id (none, or a compound one) is ARX1019 when the call needs one. Pass a schema catalog instead to declare the tables once.
  - `connectionString`: The Microsoft.Data.SqlClient connection string.
- `new ArxMsSqlDbService(string connectionString, ArxSchemaCatalog schema)`: A service with the application's schema catalog: the usual way.
  - `connectionString`: The Microsoft.Data.SqlClient connection string.
  - `schema`: The developer's schema catalog: every table's id column and keys, and the selection sets that `ArxSelectionSetValue` attributes are checked against. ARX never reads ids, keys or option tables from the database by itself. Without it, creating a record fails with ARX1016 unless the entity declares its own `IdColumn`.

Properties:

- `string ConnectionString { get; }`: The Microsoft.Data.SqlClient connection string each call opens its connection with.
- `ArxSchemaCatalog Schema { get; }`: The developer's schema catalog (table keys and selection sets); null when none was supplied.
- `IArxSelectionSetCatalog SelectionSetCatalog { get; }`: The catalog `ArxSelectionSetValue` attributes are checked against; null when none was supplied.
- `IArxProviderCapabilities Capabilities { get; }`: What SQL Server supports through ARX: joins, aggregates, paging by page number with the total, transactions and batch scopes, the multiple-row writes, Execute, full-text search, pattern conditions and Or filters. Not token paging (`PageInfo.PagingCookie` is ARX8001: page by page number), not upsert, not named secondary indexes (the database chooses its indexes).
- `const string RETURN_VALUE`: The name a procedure's RETURN value is read under, in `Outputs`.
- `bool RememberResolvedTables { get; set; }`: Without a schema catalog, keep what was resolved about each table for this service's lifetime instead of reading it again on every call. Off by default: every call then reads its tables again, always current, at the cost of extra round trips. On: each table is read once, the first time a call needs it; a schema change after that needs a new service. Has no effect on a service with a catalog, which never resolves.
- `bool Strict { get; set; }`: False (the default): a preloaded schema is what ARX knows ahead of time; tables and columns it doesn't list still work. True: the preloaded columns are an allow list. A call that names a table or a column the schema doesn't preload (written, matched, read, filtered, ordered, grouped, joined) is refused before the database with ARX1018 NotPreloaded, and reading all columns reads only the preloaded ones. Function row sources and Execute aren't covered: their columns are the routine's.

Methods:

- `Task<IArxBatchScope> BeginBatchAsync(ArxBatchOptions? options = null, CancellationToken cancellationToken = default)`: Opens a connection and a transaction for a batch scope with manual commit. For automatic commit, use `RunBatchAsync`.
  - `options`: The scope's options; null for the defaults (no savepoints).
  - `cancellationToken`: Cancels the call.
- `Task<ArxTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default)`: Begins a transaction on a connection of its own (a new `ArxMsSqlConnection`), for code that works through `IArxDataService` and so can't name the provider's connection type. Pass it to the calls, then commit it; disposing it without committing rolls it back, and closes its connection: `await using var transaction = await service.BeginTransactionAsync();`
  - `cancellationToken`: Cancels the call.
- `Task<ArxRecordId> CreateAsync(ArxEntity entity, CancellationToken cancellationToken = default)`: Inserts one entity and returns its id, which is also set on `RecordId`. A table declared NoIdColumn gives `None`.
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `cancellationToken`: Cancels the call.
- `Task<ArxRecordId> CreateAsync(ArxEntity entity, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Inserts one entity inside an ARX transaction and returns its id, which is also set on `RecordId`. Nothing is visible to other connections until the transaction commits.
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entityList, CancellationToken cancellationToken = default)`: Inserts all entities and returns their ids: one per entity, in list order, the same instances that are set on each entity's `RecordId`. A table declared NoIdColumn gives `None`.
  - `entityList`: The records to create, all or nothing; their ids come back in the same order.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Inserts all entities inside an ARX transaction, all or nothing, and returns their ids, as `CreateMultipleAsync` does. Nothing is visible to other connections until the transaction commits.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, CancellationToken cancellationToken = default)`: Inserts all entities with `schema` overriding the service's schema for this call only, and returns their ids, as `CreateMultipleAsync` does.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `schema`: Declarations for this call only: they replace the service's for the tables they declare.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, ArxTransaction transaction, CancellationToken cancellationToken = default)`: `CreateMultipleAsync` inside an ARX transaction: `schema` declares the tables for this call, and the entities mustn't.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `schema`: Declarations for this call only: they replace the service's for the tables they declare.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, CancellationToken cancellationToken = default)`: Creates the records, all or nothing. With `ReturnIds` false every id returned is `None`, and a group of 1,000 rows or more of one shape goes in by `SqlBulkCopy` (one per group, in one transaction, with constraints checked and triggers fired, as an INSERT); smaller groups take the ordinary statement, which was as fast or faster below that size. With ReturnIds true, the same as `CreateMultipleAsync`.
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, ArxTransaction transaction, CancellationToken cancellationToken = default)`: CreateMultiple with options inside an ARX transaction. A database error aborts the transaction.
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, CancellationToken cancellationToken = default)`: Deletes the record with this id: true when it was there.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Deletes the record with this id in an ARX transaction: true when it was there.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows `entity` matches and returns how many went: by default by the table's id (RecordId or the id attribute), or by a declared key or any columns (`Match`), whose values come from the entity's attributes. Attributes outside the match are ignored, so an entity read or created earlier can be passed as it is.
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxTransaction transaction, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: `DeleteAsync` inside an ARX transaction. A database error or a failed RequireSingleRow check aborts the transaction.
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync<TId>(string entityName, IReadOnlyCollection<TId> ids, CancellationToken cancellationToken = default)`: Deletes the records with these ids, all or nothing, and returns how many existed. Ids that match nothing aren't an error: the count shows them. Duplicates count once. An empty list returns 0 without touching the database. One method for every id type (1.0.0-rc.1): a list of `long`, `int`, `Guid`, `string` or `ArxRecordId`; another element type is ARX1007 UnsupportedValueType.
  - `entityName`: The table to delete from.
  - `ids`: The ids of the records to delete; ids that match nothing are left out of the count.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync<TId>(string entityName, IReadOnlyCollection<TId> ids, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Deletes the records with these ids, all or nothing, and returns how many existed, inside an ARX transaction. Ids that match nothing aren't an error: the count shows them. Duplicates count once. An empty list returns 0 without touching the database. One method for every id type (1.0.0-rc.1): a list of `long`, `int`, `Guid`, `string` or `ArxRecordId`; another element type is ARX1007 UnsupportedValueType.
  - `entityName`: The table to delete from.
  - `ids`: The ids of the records to delete; ids that match nothing are left out of the count.
  - `transaction`: The ARX transaction to run in. ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows the entities match, all or nothing, and returns how many went. Every entity uses the same match (`Match`): by id, by a declared key, or by any columns, whose values come from the entity's attributes; other attributes are ignored. Compound keys go in one statement (`DELETE … FROM … JOIN` a `VALUES` list or an `OPENJSON` source). Not strict by default: duplicates count once and nothing matching is 0. With RequireSingleRow each entity must delete exactly one row (ARX2002 or ARX2003 otherwise, nothing deleted).
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: DeleteMultiple with `schema` overriding the service's schema for this call, as for CreateMultiple. Entities in the call mustn't declare their own id column or keys (ARX1001).
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `schema`: The schema catalog: each table's id, keys, lookups and columns, and the selection sets. Null for none.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: DeleteMultiple by entities inside an ARX transaction.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, ArxTransaction transaction, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: DeleteMultiple by entities with a schema for this call, inside an ARX transaction.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `schema`: The schema catalog: each table's id, keys, lookups and columns, and the selection sets. Null for none.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a stored procedure or a function the database owns on ARX's own connection. A procedure runs as `EXEC` outside any transaction, so it may begin and commit its own; its OUTPUT values and its RETURN value (`RETURN_VALUE`) come back in `Outputs`, the tables it returns in `ResultSets`, by position. A table-valued function's rows are `ResultSets[0]` (ordered and paged when asked); a scalar function's value is `result.Value<T>()`.
  - `procedure`: The procedure or function to call, with its arguments.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxTransaction transaction, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a routine inside an ARX transaction: its writes are part of it, and a failed call aborts it. A procedure that commits or rolls back the transaction is ARX8001.
  - `procedure`: The procedure or function to call, with its arguments.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: Sets `values`' attributes on every row of its table that `filter` matches, in one `UPDATE … SET … FROM … WHERE …`, and returns how many rows changed.
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxTransaction transaction, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The update by a filter inside an ARX transaction. A database error aborts the transaction.
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes every row of the table that `filter` matches, in one `DELETE … FROM … WHERE …`, and returns how many went. The filter's rules are the update's: the table's own columns, and an empty filter is ARX1001 unless `AllRows` is set.
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxTransaction transaction, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The delete by a filter inside an ARX transaction. A database error aborts the transaction.
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Reads one record by the id Create returned; null when not found.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxTransaction transaction, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Retrieve by the id Create returned inside an ARX transaction.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Reads the one record `match` identifies: by its id (the default), a declared key or any columns (`Match`, an `ArxMatch`), with the match values taken from its attributes. Null when nothing matches; ARX2003 when a key or columns match more than one row.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxTransaction transaction, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Retrieve by a match inside an ARX transaction.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Runs a query on a table, view, materialized view or function (`Source`): its columns (including `column._lk.table.columns` direct joins), criteria, link entities, order, paging, distinct and aggregates. Every name is validated and quoted, every value sent as a parameter.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxTransaction transaction, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: RetrieveMultiple inside an ARX transaction: it sees the transaction's own uncommitted writes.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task ValidateSchemaAsync(CancellationToken cancellationToken = default)`: Compares every table in the schema catalog with the database: the table exists; its id column exists with a compatible type, identifies one row on its own (it is the primary key, or has a unique constraint or index of its own), and has a default or is an identity column when declared generated; and every declared key's columns exist and have a unique constraint or index on exactly those columns. Tables declared `NoIdColumn` skip the id checks.
  - `cancellationToken`: Cancels the call.
- `Task<ArxServerCheck> CheckServerAsync(CancellationToken cancellationToken = default)`: What the connected server allows: connects once and returns the server's version and the provider's capabilities on it. Every capability of this provider works on any supported server, so the check finds no limits; a server it can't reach is the error a call would get (ARX7005, ARX6001, …). Call it once at startup.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the row `entity` identifies and returns how many rows changed.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxTransaction transaction, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: `UpdateAsync` inside an ARX transaction. A validation error or ARX2002 when nothing matched leaves the transaction usable; a database error, or a failed RequireSingleRow check, aborts it.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates every entity, all or nothing, and returns the rows changed.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: UpdateMultiple with `schema` overriding the service's schema for this call (per table and per selection set, as for CreateMultiple). Entities in the call mustn't declare their own id column or keys (ARX1001).
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `schema`: The schema catalog: each table's id, keys, lookups and columns, and the selection sets. Null for none.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: UpdateMultiple inside an ARX transaction. A database error or a failed check aborts the transaction.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxSchemaCatalog schema, ArxTransaction transaction, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: UpdateMultiple with a schema for this call, inside an ARX transaction.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `schema`: The schema catalog: each table's id, keys, lookups and columns, and the selection sets. Null for none.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.

### ArxMsSqlConnection

class in `ARX.SDK.SQL.Services`, package `ARX.SDK.SQL`.

```csharp
public sealed class ArxMsSqlConnection : ArxConnection
```

A SQL Server connection for ARX transactions. Application code begins a transaction on it and passes the transaction to `ArxMsSqlDbService` calls; it never needs a Microsoft.Data.SqlClient type.

It wraps an `SqlConnection`, which is sealed, so ARX can't derive from it. The connection opens on the first `BeginTransactionAsync`, with the session defaults of every connection ARX opens (SQL Server has no session time zone; `XACT_ABORT` stays off so a failed statement leaves the transaction usable for batch-scope savepoints), and closes on dispose. One transaction at a time, and one call at a time. Not thread-safe.

Constructors:

- `new ArxMsSqlConnection(string connectionString)`: A connection for ARX transactions. It opens with the first BeginTransactionAsync.
  - `connectionString`: The Microsoft.Data.SqlClient connection string.

### ArxMsSqlTransaction

class in `ARX.SDK.SQL.Services`, package `ARX.SDK.SQL`.

```csharp
public sealed class ArxMsSqlTransaction : ArxTransaction
```

A SQL Server transaction begun by `BeginTransactionAsync`. Pass it to `ArxMsSqlDbService` calls; the state rules are those of `ArxTransaction`.

### ArxTransaction

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public abstract class ArxTransaction : IAsyncDisposable
```

A database transaction that ARX calls run in. Pass it to a service call, then `CommitAsync` or `RollbackAsync`. Disposing it without committing rolls it back.

ARX tracks what happened to it. A call that fails at the database aborts the transaction (`IsAborted`): later calls fail with ARX1015 before reaching the database, and `CommitAsync` rolls back and throws ARX1015 instead of appearing to commit. Some databases discard the transaction's work on any error (PostgreSQL); others undo only the failed statement (SQL Server, MySQL), so committing the rest would write only part of what the code meant: ARX rolls back on every provider, so a failed call never leaves a half-done unit of work. A call that fails validation (before the database) leaves the transaction usable. These rules live here, so every provider behaves the same; a provider supplies only the database work.

Properties:

- `ArxTransactionState State { get; }`: The transaction's state: Active until it is committed or rolled back. An aborted transaction (`IsAborted`) is still Active, because it is open and must still be rolled back; check IsAborted to know whether it can commit.
- `bool IsAborted { get; }`: True once a call in it failed at the database: it can only be rolled back.

Methods:

- `Task CommitAsync(CancellationToken cancellationToken = default)`: Commits everything written in the transaction. On an aborted transaction it rolls back and throws ARX1015. If the database refuses the commit (for example a deferred constraint or a serialization failure), the mapped error is thrown and the state is `RolledBack`. If the connection fails or times out before the database answers (ARX7005, ARX7003, or a network error), the outcome is unknown: the state is `OutcomeUnknown` and the error thrown says so, with `IsTransient` false, so retry code doesn't run the work a second time unchecked. A token cancelled before the commit starts rolls back; the commit itself isn't cancelled, because stopping it half way would leave its outcome unknown.
  - `cancellationToken`: Cancels the call.
- `Task RollbackAsync(CancellationToken cancellationToken = default)`: Rolls back everything written in the transaction. Does nothing if it is already rolled back; fails with ARX1010 if it was committed. The rollback itself isn't cancelled.
  - `cancellationToken`: Cancels the call.
- `ValueTask DisposeAsync()`: Rolls back an active transaction, then releases it. Never throws for a failed rollback.
- `static Task<ArxTransaction> BeginOnOwnConnectionAsync(ArxConnection connection, CancellationToken cancellationToken = default)`: For the providers' `IArxDataService.BeginTransactionAsync`: begins a transaction on `connection`, which the transaction then owns and closes when it is disposed. The connection is closed at once if the transaction can't begin.
  - `connection`: A new connection of the provider's own type, for this transaction only.
  - `cancellationToken`: Cancels the call.

### IArxBatchDataService

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxBatchDataService
```

A data service that can run write calls in batch scopes.

Methods:

- `Task<IArxBatchScope> BeginBatchAsync(ArxBatchOptions? options = null, CancellationToken cancellationToken = default)`: Opens a connection and a transaction, and returns a scope with manual commit: call `CommitAsync` to keep what was written. Disposing the scope without it rolls back. For automatic commit, use `RunBatchAsync`.
  - `options`: The scope's options; null for the defaults (no savepoints).
  - `cancellationToken`: Cancels the call.

### IArxBatchScope

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxBatchScope : IAsyncDisposable
```

One transaction across many write calls. Nothing written through the scope is visible to other connections until `CommitAsync`. Disposing a scope that wasn't committed rolls it back, also when an exception is passing through. Not thread-safe: make one call at a time (a concurrent call fails with ARX1014).

Properties:

- `ArxBatchState State { get; }`: The scope's state.
- `int BatchCount { get; }`: The number of calls made through the scope, successful or not. Reads count too. Each call's number (1-based) is its batch number.
- `long RowsWritten { get; }`: Rows written by successful calls that are still in the transaction; 0 once the scope is rolled back.
- `IReadOnlyList<int> FailedBatches { get; }`: The batch numbers of the calls that failed, in order.

Methods:

- `Task<ArxRecordId> CreateAsync(ArxEntity entity, CancellationToken cancellationToken = default)`: Inserts one entity inside the scope's transaction and returns its id, which is also set on `RecordId`.
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, CancellationToken cancellationToken = default)`: Inserts the entities inside the scope's transaction, all or nothing, and returns their ids: one per entity, in list order, the same instances that are set on each entity's `RecordId`. An empty list returns an empty list.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the rows `entity` matches inside the scope's transaction and returns how many changed. Nothing matched is ARX2002.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the entities inside the scope's transaction, all or nothing, and returns the rows changed. An entity that matched nothing refuses the whole call (ARX2002). An empty list returns 0.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The update by a filter inside the scope's transaction: returns how many rows changed.
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The delete by a filter inside the scope's transaction: returns how many rows went.
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, CancellationToken cancellationToken = default)`: CreateMultiple with options inside the scope's transaction.
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, CancellationToken cancellationToken = default)`: Deletes the record with this id inside the scope's transaction; false when there was none. The id converts from a `long`, `int`, `Guid` or `string`, so `DeleteAsync("account", 42L)` works as it is.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows `entity` matches inside the scope's transaction and returns how many went.
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync<TId>(string entityName, IReadOnlyCollection<TId> ids, CancellationToken cancellationToken = default)`: Deletes the records with these ids inside the scope's transaction, all or nothing, and returns how many existed. Duplicates count once. One method for every id type: a list of `long`, `int`, `Guid`, `string` or `ArxRecordId`; another element type is ARX1007 UnsupportedValueType.
  - `entityName`: The table to delete from.
  - `ids`: The ids of the records to delete; ids that match nothing are left out of the count.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows the entities match inside the scope's transaction, all or nothing, and returns how many went.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Reads one record by id (the value Create returned, or a `long`, `int`, `Guid` or `string`) inside the scope's transaction; null when not found. On the SQL providers and MongoDB it sees the scope's own writes; DynamoDB sends writes at commit, so a read before it sees only what is committed.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Reads the one record the entity matches (an ArxMatch in `Match`) inside the scope's transaction.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Runs a query inside the scope's transaction. On the SQL providers and MongoDB it sees the scope's own writes; on DynamoDB, only what is committed.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a procedure or function inside the scope's transaction: it sees the scope's writes, and a failed call is undone alone. A procedure that commits or rolls back by itself can't run in a scope (ARX8001).
  - `procedure`: The procedure or function to call, with its arguments.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task CommitAsync(CancellationToken cancellationToken = default)`: Commits everything written through the scope. If the database refuses the commit (for example a deferred constraint), the error is thrown and the scope is `RolledBack`. If the connection fails or times out before the database answers, the scope is `OutcomeUnknown` and the error, not transient, says the work may or may not be saved. A token cancelled before the commit starts rolls the scope back; the commit itself isn't cancelled, because stopping it half way would leave its outcome unknown.
  - `cancellationToken`: Cancels the call.
- `Task RollbackAsync(CancellationToken cancellationToken = default)`: Rolls back everything written through the scope. Does nothing if the scope is already rolled back; fails with ARX1010 if it was committed. The rollback itself isn't cancelled.
  - `cancellationToken`: Cancels the call.

### ArxBatchOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxBatchOptions
```

Options for a batch scope.

Properties:

- `bool? Savepoints { get; init; }`: When true, each call made through the scope runs inside its own savepoint. A failed call is then undone alone: the calls before it stay in the transaction, the scope stays `Active`, and the developer decides whether to continue, retry or roll back. When false or null (the default), any failed call rolls back the whole scope, on every provider, so the same code ends the same way on every database: a body that catches the error has nothing saved, and `RunBatchAsync` throws ARX1015 when it returns. Ask for savepoints where a failed call should be undone alone; only PostgreSQL, SQL Server and MySQL have them (`Savepoints`), and true on MongoDB or DynamoDB is refused with `ArxNotSupportedException`.

## Entities and values

A record, its id, and the values with a meaning of their own: a reference to another record, a selection set code, JSON, bytes, an attribute left out.

### ArxEntity

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public class ArxEntity
```

A record of one table: its name (`EntityName`), its attributes (column name to value) and, once written or read, its id (`RecordId`). Set a value with `entity["name"] = "Contoso"`.

Reading values: `entity["name"]` is null both for a NULL column and for an attribute the record doesn't have (a column not read, or a mistyped name), so use `Contains` to tell them apart. Names are matched ignoring case, on read as on write (`entity["Name"]` finds `name`). `GetAttributeValue{T}` converts numbers when nothing is lost (ARX4001 when the number doesn't fit), reads a lookup or a record id as its id, and a UTC or Local `DateTime` as a `DateTimeOffset` (and back); any other mismatch is ARX4004. A declared lookup reads back as an `ArxEntityReference`. `entity.Attributes["x"]` is the dictionary underneath: it throws `KeyNotFoundException` for a missing attribute, where the indexer returns null.

Constructors:

- `new ArxEntity()`: An entity with no table yet: set EntityName before using it.
- `new ArxEntity(string entityName)`: An empty record of this table.
  - `entityName`: The table, or `schema.table`.
- `new ArxEntity(string entityName, ArxAttributeCollection attributes)`: An entity with the given attribute collection: a provider reading rows passes one it built.
  - `entityName`: The table, or `schema.table`.
  - `attributes`: The attributes to use as they are (not copied).
- `new ArxEntity(string entityName, int attributeCapacity)`: An entity with room for `attributeCapacity` attributes, so a provider that knows how many it reads (a result row) fills it without the dictionary growing.
  - `entityName`: The table, or `schema.table`.
  - `attributeCapacity`: How many attributes the entity will hold.

Properties:

- `ArxRecordId? RecordId { get; set; }`: The record's id, of any declared id type: read it with `AsInt64()`, `AsString()`, `AsGuid()` or `Value`. Set by Create and by every read that knows the table's id. Create reads the id to write from the attributes, never from this property, so an entity ARX created or read can be created again as a copy. An id your code sets here before a Create is refused (ARX1001) unless the id attribute holds the same id: to give a record its id, set the id attribute (`entity["id"] = …`).
- `ArxIdColumn? IdColumn { get; set; }`: The id column for this entity, when no schema declares its table: a service with no schema catalog, and no schema passed to the call. With a schema, setting it is refused (ARX1001), because a table is declared in one place; to declare a table differently for one call, pass a schema to that call instead. Null (the default) means the schema's declaration is used. `NoIdColumn` for a table with no id.
- `IReadOnlyList<ArxKey>? Keys { get; set; }`: The table's business keys for this entity, when no schema declares its table; with a schema, setting them is refused (ARX1001). Optional: null (the default) means the schema's keys, or none. Keys alone don't declare an id. Create doesn't use them; Update and Delete can find rows by them.
- `string EntityName { get; set; }`: The table (or `schema.table`) the record belongs to.
- `ArxAttributeCollection Attributes { get; set; }`: The record's values by column name. Create and Update write exactly these; a read fills them.
- `object? this[string attributeName] { get; set; }`: A column's value: null when the record has no such attribute. Setting it adds or replaces the attribute.

Methods:

- `bool Contains(string attributeName)`: True when the entity has the attribute (names are matched ignoring case).
  - `attributeName`: The attribute (column) name, matched ignoring case.
- `T? GetAttributeValue<T>(string attributeName)`: The attribute's value as `T`, or its default when the attribute is missing or null (so `GetAttributeValue<int>` of a NULL column is 0, and `GetAttributeValue<int?>` is null: ask for a nullable type to tell NULL from 0. `Contains` is true for a column that was read as NULL).
  - `attributeName`: The attribute (column) name, matched ignoring case.
- `ArxEntityReference ToEntityReference(string? primaryColumnName = null)`: A reference to this entity's record, for a lookup on another entity. Its `Name` is the value of `primaryColumnName` (a lookup's own name when the column is one), or null when no column is named or the entity doesn't have it.
  - `primaryColumnName`: The column whose value names the record (a display name), or null.

### ArxEntityCollection

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxEntityCollection
```

The rows a RetrieveMultiple returns (`Entities`), whether another page follows (`HasNextPage`), and the total (`TotalRecordCount`) when the query asked for it.

Constructors:

- `new ArxEntityCollection()`: An empty collection.
- `new ArxEntityCollection(List<ArxEntity> list)`: A collection of these rows (the list itself, not a copy).
  - `list`: The rows. The collection uses this list itself, not a copy.

Properties:

- `List<ArxEntity> Entities { get; }`: The rows, in the query's order.
- `string? EntityName { get; set; }`: The row source the rows were read from.
- `int TotalRecordCount { get; set; }`: Every row that matched, across all pages. Only set when the query asked for it (ReturnTotalRecordCount); without paging, the number of rows read.
- `int CurrentPage { get; set; }`: The page these rows are (1 when the query isn't paged).
- `int TotalPageCount { get; set; }`: How many pages there are; only set when the total was asked for.
- `bool HasNextPage { get; set; }`: Whether another page follows. Always exact: ARX reads one row more than the page to know.
- `string? PagingCookie { get; set; }`: Token paging: pass this to the next query's `ArxPagingInfo.PagingCookie` to read the next page. Null when no page follows, and always null from a provider without `TokenPaging`. On such a provider (PostgreSQL, SQL Server, MySQL) page by `ArxPagingInfo.PageNumber` instead: a loop that only passes this cookie on reads the first page again, because a null cookie means "the first page".
- `ArxEntity this[int index] { get; set; }`: The row at this position.

### ArxRecordId

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxRecordId : IEquatable<ArxRecordId>
```

The id of one record: the value of its table's id column, of any declared id type. Returned by Create and set on `RecordId`. `None` for a table declared `NoIdColumn`. Immutable; equal when the column and value are equal.

Created with:

- `implicit operator ArxRecordId(long value)`: An id given as its value alone, so `service.RetrieveAsync("account", 42L)` works through `IArxDataService` too: the service takes the column from the table's declaration. Its `Column` is empty; use `Of` to name it.
  - `value`: The id's value.
- `implicit operator ArxRecordId(int value)`: An int id given as its value alone (see the `long` conversion).
  - `value`: The id's value.
- `implicit operator ArxRecordId(Guid value)`: A Guid id given as its value alone (see the `long` conversion).
  - `value`: The id's value.
- `implicit operator ArxRecordId?(string? value)`: A text id given as its value alone (see the `long` conversion); null stays null.
  - `value`: The id's value.
- `ArxRecordId.Of(string column, object value)`: An id with its column and value, for example to update or delete by id.
  - `column`: The id column's name.
  - `value`: The id's value.

Properties:

- `static ArxRecordId None { get; }`: No id: what Create returns for a table declared `NoIdColumn`.
- `string Column { get; }`: The id column's name. Empty for `None`, and for an id given as its value alone.
- `bool HasValue { get; }`: False for `None`.
- `object Value { get; }`: The id's value, in the declared type.

Methods:

- `long AsInt64()`: The value of an integer id (short, int or long).
- `int AsInt32()`: The value of an integer id as an int.
- `Guid AsGuid()`: The value of a Guid id.
- `string AsString()`: The value of a string id.
- `bool Equals(ArxRecordId? other)`: True when `other` has an equal value (integers compare by value, whatever their width) and the same id column when both name one, so an id given as a plain value equals the id Create returned. Two ids without a value are equal.
  - `other`: The id to compare with, or null.
- `static bool operator ==(ArxRecordId? left, ArxRecordId? right)`: True when the ids are equal (see `Equals`); two nulls are equal.
  - `left`: An id, or null.
  - `right`: An id, or null.
- `static bool operator !=(ArxRecordId? left, ArxRecordId? right)`: True when the ids differ.
  - `left`: An id, or null.
  - `right`: An id, or null.

### ArxEntityReference

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public class ArxEntityReference
```

A lookup: a reference to a record of another table, by that table's name and the record's id. Written to a lookup column as the id; the table name tells ARX which table the id belongs to, so a schema can check it.

The id can be of any supported id type: short, int, long, decimal, string, Guid, DateOnly or DateTime, or the `ArxRecordId` that Create returned. Every constructor takes the table name first, then the id, then an optional display name.

Constructors:

- `new ArxEntityReference()`: An empty reference; set its table and id.
- `new ArxEntityReference(string entityName, long id, string? name = null)`: A reference by an integer id (short, int and long all fit).
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's integer id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, Guid id, string? name = null)`: A reference by a uuid id.
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's uuid id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, string id, string? name = null)`: A reference by a text id (a country code, a SKU).
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's text id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, decimal id, string? name = null)`: A reference by a decimal id.
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's decimal id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, DateOnly id, string? name = null)`: A reference by a date id.
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's date id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, DateTime id, string? name = null)`: A reference by a timestamp id.
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The referenced record's timestamp id.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.
- `new ArxEntityReference(string entityName, ArxRecordId id, string? name = null)`: A reference by the id Create returned (`await service.CreateAsync(account)`), of any type.
  - `entityName`: The referenced table: the table the id belongs to.
  - `id`: The id CreateAsync returned for the referenced record, of any id type.
  - `name`: Its display name, if you have it; optional, ARX doesn't write it.

Properties:

- `ArxRecordId? RecordId { get; }`: The referenced record's id, of any supported type; null when none was given. This is what Create writes to the lookup column. `None` (a record of a table with no id column) can't be referenced.
- `long Id { get; set; }`: **Obsolete.** Id is only an integer id: 0 for a Guid or text id. Use RecordId (RecordId.Value, AsInt64(), AsGuid(), AsString()). The referenced record's id when it's an integer; 0 otherwise (a Guid or text id reads as 0). Setting it sets `RecordId`. Use `RecordId`, which holds an id of any type.
- `Guid Guid { get; set; }`: **Obsolete.** Guid is only a Guid id: Guid.Empty for an integer or text id. Use RecordId (RecordId.Value, AsGuid()). The referenced record's id when it's a Guid; `Guid.Empty` otherwise. Setting it sets `RecordId`. Use `RecordId`, which holds an id of any type.
- `string EntityName { get; set; }`: The referenced table: checked against the schema when there is one (it must be declared, with an id of the reference's type).
- `string? Name { get; set; }`: The referenced record's display name, if known. Not written by Create.

### ArxSelectionSetValue

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSelectionSetValue
```

A selection set (option set, picklist) value: the option's code, checked against the set named `SetName` in the developer's `IArxSelectionSetCatalog` and written in that set's storage form. A plain `int` or `string` attribute is written as is, without catalog checks.

Create a single-choice value with the constructor and a multiple-choice value with `Multiple`. Values read back through `ArxSelectionSetExtensions.GetSelectionSet` also carry the matched `Options`, so `DisplayText` and `IsDefined` are available.

Constructors:

- `new ArxSelectionSetValue(string setName, object value)`: A single-choice value: `value` is the option's code (an integer, string, char, bool, decimal or Guid).
  - `setName`: The catalog set to check against. Required when writing; a missing name is reported as ARX1006 by the provider.
  - `value`: The option's code. Not null, and not a collection (use `Multiple`).

Created with:

- `ArxSelectionSetValue.Multiple(string setName, params object[] values)`: A multiple-choice value. An empty list means no option is chosen.
  - `setName`: The selection set's name in the catalog.
  - `values`: The chosen codes.
- `ArxSelectionSetValue.Multiple(string setName, IEnumerable values)`: A multiple-choice value from any sequence of codes (`int[]`, `List<string>`, …). An empty sequence means no option is chosen. A single `string` is one code, not a sequence of characters.
  - `setName`: The selection set's name in the catalog.
  - `values`: The chosen codes.

Properties:

- `string SetName { get; }`: The catalog set this value belongs to.
- `object? Value { get; }`: The single-choice code; null for a multiple-choice value.
- `IReadOnlyList<object> Values { get; }`: Every chosen code: one for a single-choice value, zero or more for a multiple-choice value.
- `bool IsMultiple { get; }`: True when created with `Multiple` or decoded from a multiple-choice set.
- `IReadOnlyList<ArxSelectionSetOption?>? Options { get; }`: The catalog options matching `Values`, in the same order, when the value was decoded from storage; an entry is null when the stored code isn't in the set. Null for values created by the caller.
- `bool IsDefined { get; }`: True when the value was decoded and every stored code is an option of the set.
- `string? DisplayText { get; }`: The display text of the matched option (single choice), or of every matched option joined with ", " in stored order (multiple choice). Null when not decoded, or when a single-choice code isn't in the set.

### ArxJsonB

class in `ARX.SDK.Models`, package `ARX.SDK`.

```csharp
public class ArxJsonB
```

A JSON value: written to a `jsonb` or `json` column as its `SerializedValue` text, and what those columns read back as.

Properties:

- `string? SerializedValue { get; set; }`: The JSON text, as written to the column or read back from it.

### ArxBytea

class in `ARX.SDK.Models`, package `ARX.SDK`.

```csharp
public class ArxBytea
```

Binary data for a binary column (`Data`): PostgreSQL `bytea`, SQL Server `varbinary`, MySQL `BLOB` or `VARBINARY`, a MongoDB binary, a DynamoDB B attribute. A plain `byte[]` works too.

Properties:

- `byte[]? Data { get; set; }`: The bytes to write.

### ArxIgnore

class in `ARX.SDK.Models`, package `ARX.SDK`.

```csharp
public class ArxIgnore
```

An attribute value meaning "leave this column out": Create and Update don't write an attribute set to `new ArxIgnore()`.

## The schema catalog

What the developer declares once: each table's id column, its business keys, lookups, display names, and the selection sets.

### ArxSchemaCatalog

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSchemaCatalog : IArxSelectionSetCatalog
```

What the developer declares about the database: every table's id column and keys, and the selection sets. Build it once at startup and give it to the service: `new ArxMsSqlDbService(connectionString, schema)`. ARX never reads ids, keys or option tables from the database by itself. Immutable and thread-safe.

Properties:

- `IReadOnlyCollection<ArxTableDefinition> Tables { get; }`: Every declared table, in the order added.
- `ArxSelectionSetCatalog SelectionSets { get; }`: The selection sets.

Methods:

- `string ToJson()`: The catalog's tables as JSON: ids, keys, lookups, display names, columns with their types, and for a preload the reason each table was added and its notes. Reload it with `ArxSchemaCatalog.Create().AddJson(json)`. Selection sets aren't written: they are code. ARX doesn't write the file: the application decides.
- `static ArxSchemaCatalogBuilder Create()`: Starts a catalog: declare each table's id, keys, lookups and selection sets, then call Build.
- `bool TryGetTable(string name, out ArxTableDefinition table)`: Finds a table by its exact name (table names are case-sensitive).
  - `name`: The table, as the database names it.
  - `table`: The table's declaration when found; otherwise null.
- `string? ClosestTable(string name)`: The declared table whose name is closest to `name`, for an error that names an undeclared table: the same letters in another case first (table names are case-sensitive), then a name within two edits (`acount` for `account`). Null when no declared name is that close.
  - `name`: A table name the catalog doesn't declare.
- `bool TryGetSet(string name, out ArxSelectionSetDefinition set)`: Gets a selection set by name; false when the catalog has none of that name.
  - `name`: The selection set's name.
  - `set`: The set when found; otherwise null.

### ArxSchemaCatalogBuilder

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSchemaCatalogBuilder
```

Builds an `ArxSchemaCatalog`. Not thread-safe; build once, at startup.

Methods:

- `ArxSchemaCatalogBuilder Column(string table, ArxColumnDefinition column)`: Declares a column of a table with its type. Done by a preload; by hand for a table the preload can't read.
  - `table`: The table, as the database names it.
  - `column`: The column: its name, .NET type, database type and whether it takes null.
- `ArxSchemaCatalogBuilder AllColumns(string table)`: Marks a table's declared columns as all of its columns (a preload of every column).
  - `table`: The table, as the database names it.
- `ArxSchemaCatalogBuilder Reason(string table, string reason)`: Why a table is in the catalog: `"requested"`, `"added: referenced by …"`.
  - `table`: The table, as the database names it.
  - `reason`: Why: `"requested"`, or `"added: referenced by …"`.
- `ArxSchemaCatalogBuilder Note(string table, string note)`: Something a preload left out of a table, and why.
  - `table`: The table, as the database names it.
  - `note`: What was left out, and why.
- `ArxSchemaCatalogBuilder AddJson(string json)`: Adds the tables of a catalog written by `ToJson` (a saved preload): ids, keys, lookups, display names, columns, reasons and notes. Selection sets aren't in the JSON: add them in code.
  - `json`: A catalog saved by `ToJson`.
- `ArxSchemaCatalogBuilder Table(string name, ArxIdColumn idColumn)`: Declares a table and its id column, or `NoIdColumn`.
  - `name`: The table, as the database names it.
  - `idColumn`: Its id column (`Generated{T}`, `Supplied{T}`), or `NoIdColumn`.
- `bool DeclaresTable(string name)`: True when this builder already declares the table (with `Table`).
  - `name`: The table, as the database names it.
- `bool DeclaresKey(string table, params string[] columns)`: True when this builder already declares this key of the table, its columns in any order (with `Key`).
  - `table`: The table, as the database names it.
  - `columns`: The key's columns.
- `bool DeclaresColumn(string table, string column)`: True when this builder already declares the column of the table (with `Column`), its name matched ignoring case.
  - `table`: The table, as the database names it.
  - `column`: The column's name.
- `ArxSchemaCatalogBuilder Key(string table, params string[] columns)`: Declares a business key of a table: one column, or several for a compound key. A table can have several keys.
  - `table`: The table, as the database names it.
  - `columns`: The key's columns: one, or several for a compound key.
- `ArxSchemaCatalogBuilder Lookup(string table, string column, string referencedTable)`: Declares a lookup column: `column` of `table` holds the id of a record of `referencedTable`, which must be declared too. Retrieve reads it back as an `ArxEntityReference`.
  - `table`: The table, as the database names it.
  - `column`: The column that holds the referenced record's id.
  - `referencedTable`: The table it refers to; it must be declared with an id.
- `ArxSchemaCatalogBuilder Version(string table, string column, bool required = false)`: Declares the column that holds a record's version, for optimistic concurrency: an integer column, not the id or a key. See `VersionColumn`. With `required`, an Update must carry the version it read (`VersionRequired`).
  - `table`: The table, as the database names it.
  - `column`: The integer column ARX sets to 1 on create and adds one to on every update.
  - `required`: True to refuse an update or delete whose entity doesn't carry the version (ARX1001); false to let the last writer win.
- `ArxSchemaCatalogBuilder Alias(string table, string attribute, string databaseName)`: Declares a name alias: code uses `attribute`, a valid ARX name (ASCII letters, digits and underscores, starting with a letter or underscore), for the column the database names `databaseName`, such as `.Alias("customer", "first_name", "first-name")`. The provider quotes and escapes the database name by its own rules, in writes, reads, filters, order, matches and keys, and reads the column back as the attribute. The table's id, keys, lookups and version are declared by their attribute names. A link entity's columns keep the identifier rule in this version.
  - `table`: The table, as the database names it.
  - `attribute`: The attribute (column) name.
  - `databaseName`: The column's name in the database, quoted by the provider's rules.
- `ArxSchemaCatalogBuilder DisplayName(string table, string column)`: Declares the column that names a record of `table` to a person.
  - `table`: The table, as the database names it.
  - `column`: The column whose value is a lookup's `Name`.
- `ArxSchemaCatalogBuilder DisplayName(string table, string[] columns, string delimiter = " ")`: Declares the columns that name a record of `table`, joined by `delimiter` (`.DisplayName("contact", new[] { "first_name", "last_name" }, " ")`). NULL parts are skipped; the delimiter may be empty.
  - `table`: The table, as the database names it.
  - `columns`: The columns joined to make the name.
  - `delimiter`: The text between them.
- `ArxSchemaCatalogBuilder Add(ArxSelectionSetDefinition set)`: Adds a selection set (see `Add`).
  - `set`: A selection set built elsewhere.
- `ArxSchemaCatalogBuilder Add(string name, ArxSelectionSetKind kind, params (object Value, string DisplayText)[] options)`: Adds a single-choice selection set.
  - `name`: The set's name, used when writing and reading its values.
  - `kind`: What its codes are: integers, text or single characters.
  - `options`: The options: each code and its display text.
- `ArxSchemaCatalogBuilder Add(string name, ArxSelectionSetKind kind, ArxSelectionSetMultiplicity multiplicity, params (object Value, string DisplayText)[] options)`: Adds a selection set with the given storage form.
  - `name`: The set's name, used when writing and reading its values.
  - `kind`: What its codes are: integers, text or single characters.
  - `multiplicity`: One option per column, or several stored as an array.
  - `options`: The options: each code and its display text.
- `ArxSchemaCatalogBuilder AddEnum<TEnum>(string? name = null)`: Adds a single-choice Integer selection set from a .NET enum.
  - `name`: The set's name; the enum's name when null.
- `ArxSchemaCatalogBuilder AddFlagsEnum<TEnum>(string? name = null)`: Adds a Flags selection set from a `[Flags]` enum.
  - `name`: The set's name; the enum's name when null.
- `ArxSchemaCatalog Build()`: Builds the catalog. Throws for a table declared twice, a key of an undeclared table, or the same key twice.

### ArxIdColumn

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxIdColumn : IEquatable<ArxIdColumn>
```

A table's id column, declared by the developer: the one column that identifies a record. Every table declares exactly one, or `NoIdColumn` when it has no id column.

**Generated**: the database produces the value when the entity doesn't give one (an identity column, a sequence, a default). A value the entity does give is written. **Supplied**: the caller always gives the value (a natural id such as a country code or a SKU, a client-generated Guid).

Created with:

- `ArxIdColumn.Generated<T>(string name)`: An id column the database fills in when the entity has no value for it (identity, sequence, default).
  - `name`: The id column's name.
- `ArxIdColumn.Supplied<T>(string name)`: An id column the caller always gives a value for.
  - `name`: The id column's name.

Properties:

- `static ArxIdColumn NoIdColumn { get; }`: The table has no id column: a log or a history table, or a table identified only by a combination of columns, such as a compound primary key (declare those columns as a key). Create stores its rows and returns `None`.
- `static ArxIdColumn NoPrimaryKey { get; }`: **Obsolete.** Use ArxIdColumn.NoIdColumn: the same declaration under a name that also fits a compound primary key. The former name of `NoIdColumn`: it read as wrong for a table with a compound primary key.
- `string Name { get; }`: The column name (compared with attribute names case-insensitively, like every column). Empty for `NoIdColumn`.
- `Type Type { get; }`: The .NET type the id is read and written as.
- `bool IsGenerated { get; }`: True when the database can produce the value.
- `bool IsNoIdColumn { get; }`: True for `NoIdColumn`.
- `bool IsNoPrimaryKey { get; }`: **Obsolete.** Use IsNoIdColumn. The former name of `IsNoIdColumn`.
- `bool IsInteger { get; }`: True when the id is a short, int or long.

Methods:

- `bool Equals(ArxIdColumn? other)`: Equal when both are `NoIdColumn`, or have the same name (ignoring case), type and generated flag.
  - `other`: The id column to compare with.

### ArxKey

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxKey : IEquatable<ArxKey>
```

A business key of a table: one or more columns whose values identify a record, such as `account_number`, or `region` and `sku` together. Optional: a table whose rows may repeat declares none. Create doesn't use keys (the database's unique constraints enforce them); Update and Delete can find rows by them.

Constructors:

- `new ArxKey(params string[] columns)`: A key of one column, or of several for a compound key.
  - `columns`: The key's columns: one, or several that identify a row together.

Properties:

- `IReadOnlyList<string> Columns { get; }`: The key's columns, as declared.
- `bool IsCompound { get; }`: True when the key has more than one column.

Methods:

- `bool Equals(ArxKey? other)`: Equal when both keys have the same columns, in any order, ignoring case.
  - `other`: The key to compare with.

### ArxTableDefinition

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxTableDefinition
```

A table the developer declared: its id column and its keys. Immutable and thread-safe.

Created with:

- `ArxTableDefinition.Define(string table, ArxIdColumn idColumn, IReadOnlyList<ArxKey>? keys = null)`: A table definition declared on an entity (`IdColumn`, `Keys`) rather than in a schema catalog. The same rules apply: an id column (or `NoIdColumn`), and no key twice.
  - `table`: The table.
  - `idColumn`: Its id column, or ArxIdColumn.NoIdColumn.
  - `keys`: Its business keys; none by default.

Properties:

- `IReadOnlyDictionary<string, ArxColumnDefinition> Columns { get; }`: The table's columns and their types, by name (lower case), when the schema was preloaded with data types; empty for a table declared by hand or preloaded keys only. With `Strict`, the only columns a call may use.
- `bool HasColumns { get; }`: True when the columns are known (preloaded with data types).
- `bool HasAllColumns { get; init; }`: True when the preload loaded every column of the table (an empty column list), not a chosen few.
- `string? Reason { get; }`: Why a preload added this table: `"requested"`, or `"added: referenced by account.primary_contact_id"`; null when declared by hand.
- `IReadOnlyList<string> Notes { get; }`: What a preload left out and why (a column ARX can't name, a key not fully loaded, a reference beyond the depth).
- `string? VersionColumn { get; init; }`: The column that holds the record's version (optimistic concurrency), or null. A provider that offers it (capability OptimisticConcurrency) writes 1 on Create when the entity gives none, adds one on every Update, and checks an Update or Delete against the version the entity carries: changed since it was read is ARX2004. A provider that doesn't refuses writes to the table with ARX8001.
- `bool VersionRequired { get; init; }`: True when an Update of the table must carry the version it read (`.Version(table, column, required: true)`): an update without it is refused with ARX1001 instead of writing unconditioned. False (the default) lets an update without a version through, still adding one to the version so other writers see the change.
- `IReadOnlyDictionary<string, string> Aliases { get; init; }`: The table's name aliases: attribute name (case-insensitive) to the column's name in the database, for a column whose name isn't a valid ARX name (`first-name`, `order.total`). Code uses the attribute; the provider sends the database name, quoted by its own rules, and reads the column back as the attribute. Only declared names pass: a database name never comes from a call. Empty when none are declared.
- `bool HasAliases { get; }`: True when the table declares aliases.
- `IReadOnlyDictionary<string, string> Lookups { get; }`: The lookup columns: column name (lower case) to the table it refers to. A lookup column reads back as an `ArxEntityReference` whose id has the referenced table's declared type. Empty when none are declared.
- `ArxDisplayName? DisplayName { get; }`: How a record of this table is named to a person; null when not declared.
- `string Name { get; }`: The table (entity) name, exactly as declared (table names are case-sensitive).
- `ArxIdColumn IdColumn { get; }`: The id column, or `NoIdColumn`.
- `IReadOnlyList<ArxKey> Keys { get; }`: The business keys, as declared. Empty when the table declares none.
- `bool HasId { get; }`: True unless the table is declared `NoIdColumn`.

Methods:

- `bool TryGetDatabaseName(string attribute, out string databaseName)`: The database name of `attribute` when it is an alias; false for an ordinary name.
  - `attribute`: The attribute name code uses.
  - `databaseName`: The column's name in the database when the attribute has an alias; otherwise null.
- `bool TryGetAttribute(string databaseName, out string attribute)`: The attribute a database column is read back as, when the column has an alias; false for an ordinary column.
  - `databaseName`: The column's name in the database.
  - `attribute`: The attribute name its alias gives it, when it has one; otherwise null.
- `ArxRecordId IdOf(long value)`: The id of a record of this table from an integer value, with no boxing. For providers reading ids back.
  - `value`: The id's value.
- `ArxRecordId IdOf(object value)`: The id of a record of this table from its value, which must have the declared type.
  - `value`: The id's value.

### ArxDisplayName

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxDisplayName
```

How a record is named to a person: one column, or several joined by a delimiter, NULL parts skipped. Declared in the schema with `.DisplayName(table, column)` or `.DisplayName(table, columns, delimiter)`.

Properties:

- `IReadOnlyList<string> Columns { get; }`: The columns, in the order they are joined.
- `string Delimiter { get; }`: What goes between the parts; may be empty.

### ArxSelectionSetDefinition

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSelectionSetDefinition
```

One selection set: its kind, storage form and options. Immutable and thread-safe. Validates selection set values and converts them to and from the stored form, so every provider applies the same rules.

Constructors:

- `new ArxSelectionSetDefinition(string name, ArxSelectionSetKind kind, IEnumerable<ArxSelectionSetOption> options, ArxSelectionSetMultiplicity multiplicity = ArxSelectionSetMultiplicity.Single, string? databaseTypeName = null, string delimiter = ",")`: A selection set and its options, checked for consistency.
  - `name`: The name selection set values refer to.
  - `kind`: What the codes are, matching the column.
  - `options`: Each code with its display text, order and whether it is still active.
  - `multiplicity`: One code (Single), or several and how they are stored.
  - `databaseTypeName`: The PostgreSQL enum type, for a DatabaseEnum set.
  - `delimiter`: The separator of a Delimited set.

Properties:

- `string Name { get; }`: The name selection set values refer to.
- `ArxSelectionSetKind Kind { get; }`: What the codes are, matching the column that stores them.
- `ArxSelectionSetMultiplicity Multiplicity { get; }`: One code, or several and in which storage form.
- `string? DatabaseTypeName { get; }`: The database enum type a DatabaseEnum set casts to (for example "mood"). The provider validates and quotes it.
- `string Delimiter { get; }`: The separator of a Delimited set.
- `IReadOnlyList<ArxSelectionSetOption> Options { get; }`: The options, by `Order` (stable for equal orders).
- `Type CodeType { get; }`: The CLR type of every code, taken from the options. Single values and array elements are written as this type.

Methods:

- `bool TryGetOption(object code, out ArxSelectionSetOption option)`: Finds the option with this code. A code of another kind (a string for an Integer set) isn't found.
  - `code`: The option's code.
  - `option`: The option when found; otherwise null.
- `object ToStoredValue(ArxSelectionSetValue value, string? entityName = null, string? attributeName = null, string? provider = null)`: Validates `value` against this set and returns what the provider writes: the option's own code (Single), a typed array (Array), the OR of the codes (Flags), the joined codes (Delimited) or an `ArxJsonB` array (Json). Multiple-choice forms list the options in set order.
  - `value`: The value to write.
  - `entityName`: The table, for the error message.
  - `attributeName`: The column, for the error message.
  - `provider`: The provider's name, for the error.
- `ArxSelectionSetValue? FromStoredValue(object? stored)`: Decodes a stored column value back into an `ArxSelectionSetValue` with its matched options. A stored code that isn't in the set is kept, with a null option (`IsDefined` false); reading never fails because of data that predates the catalog. Null gives null.
  - `stored`: The value read from the column.

### ArxSelectionSetOption

record in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed record ArxSelectionSetOption
```

One option of a selection set. Retired options (`IsActive` false) stay readable but can't be written.

### ArxSelectionSetKind

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxSelectionSetKind
```

What a selection set's codes are, matching the column that stores them.

Values:

- `Integer`: Integer codes (1, 2, 3; enum values): `byte` to `long`.
- `String`: String codes ("ACTIVE", "red", "Colors~2").
- `Character`: Single-character codes ('A', 'I').
- `Boolean`: Two options stored as a boolean.
- `Decimal`: Decimal codes.
- `Guid`: Guid codes.
- `DatabaseEnum`: A native database enum, written as its label with a cast to `DatabaseTypeName` where the database needs one.

### ArxSelectionSetMultiplicity

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxSelectionSetMultiplicity
```

How many options a record holds, and in which storage form when it's more than one.

Values:

- `Single`: One option, stored as its code.
- `Array`: Several options, stored as a typed array (PostgreSQL arrays, MongoDB arrays, DynamoDB sets).
- `Flags`: Several options, stored as the bitwise OR of their codes. Integer sets only; every code is a power of two.
- `Delimited`: Several options, stored as their codes joined with `Delimiter`.
- `Json`: Several options, stored as a JSON array of their codes.

## Preloading the schema

Reading the tables' ids, keys, lookups and column types from the database once, when the service is set up.

### ArxMsSqlPreLoad

static class in `ARX.SDK.SQL.Services`, package `ARX.SDK.SQL`.

```csharp
public static class ArxMsSqlPreLoad
```

Loads an `ArxPreLoadTable` from a SQL Server database.

Methods:

- `static Task<ArxSchemaCatalog> LoadAsync(this ArxPreLoadTable preload, string connectionString, Action<ArxSchemaCatalogBuilder>? configure = null, CancellationToken cancellationToken = default)`: Reads the requested tables from the database once (call it at startup, at service registration) and returns the schema catalog for `new ArxMsSqlDbService(connectionString, catalog)`: each table's id, business keys, lookups and, in `DataTypes`, its columns' types; the tables the loaded columns reference are added with the reason (`Reason`). Operations never read the catalog again.
  - `preload`: The tables to read, and how much of each (ArxPreLoadMode).
  - `connectionString`: The database to read them from; used for this call only.
  - `configure`: Adds what the database can't say: display names, selection sets, hand-declared tables.
  - `cancellationToken`: Cancels the reads.

### ArxPreLoadTable

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxPreLoadTable
```

A preload into a schema catalog at service setup: the registered tables, and what to read of them. Tables their loaded columns reference are added, with the reason. The provider loads it (for example `await preload.LoadAsync(connectionString)`).

Constructors:

- `new ArxPreLoadTable(ArxPreLoadTableRegister tables, ArxPreLoadMode mode = ArxPreLoadMode.DataTypes)`: A preload of the registered tables. Nothing is read until the provider's LoadAsync runs.
  - `tables`: The tables to read, each with its columns (none for every column). The preload keeps a copy.
  - `mode`: DataTypes (the default) reads the keys and every loaded column's type; KeysOnly reads the id, business keys and lookups only.

Properties:

- `IReadOnlyDictionary<string, IReadOnlyList<string>> Tables { get; }`: Each requested table and its columns (empty: all of them).
- `ArxPreLoadMode Mode { get; }`: What the preload reads: DataTypes or KeysOnly.
- `int ReferenceDepth { get; init; }`: How many references deep referenced tables are added (3 by default; 0 adds none).

### ArxPreLoadTableRegister

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxPreLoadTableRegister
```

The tables a preload reads: one `PreLoadTable` call per table, with the columns to load, or none for all of them. A mistake is refused on the call that makes it.

Properties:

- `IReadOnlyDictionary<string, IReadOnlyList<string>> Tables { get; }`: Each registered table and its columns (empty: all of them), in the order registered.

Methods:

- `ArxPreLoadTableRegister PreLoadTable(string table, string[]? columns = null)`: Registers `table` (`"table"` or `"schema.table"`) with the columns to load: `null` or `[]` for every column, a list for only those (the id column is always loaded).
  - `table`: The table to read, as the database names it.
  - `columns`: The columns to read (the id is always read); null for every column.

### ArxPreLoadMode

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxPreLoadMode
```

What a preload reads.

Values:

- `DataTypes`: "Fast": the id, business keys, lookups, and every loaded column's type. Needed for `Strict`.
- `KeysOnly`: "Convenient": the table keys only (the id, business keys, lookups), no column types.

### ArxColumnDefinition

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxColumnDefinition
```

A column a preload found: its name, the .NET type ARX reads it as, the database's type and traits.

Constructors:

- `new ArxColumnDefinition(string name, Type type, string databaseType, bool isNullable, ArxColumnTraits traits = ArxColumnTraits.None)`: A column definition, as a preload creates it (or by hand, for a table a preload can't read).
  - `name`: The column name.
  - `type`: The .NET type ARX reads the column as.
  - `databaseType`: The database's type name (for an array, its element type).
  - `isNullable`: Whether the column accepts NULL.
  - `traits`: What the database type is beyond its .NET type: an enum, a composite, an array, JSON, a default.

Properties:

- `string Name { get; }`: The column name.
- `Type Type { get; }`: The .NET type values of this column read back as (Retrieve's value mapping), and are expected as.
- `string DatabaseType { get; }`: The database's type name, as it names it (for example `int8` or `varchar` in PostgreSQL, `nvarchar` in SQL Server; for an array, its element's).
- `bool IsNullable { get; }`: Whether the column accepts NULL.
- `ArxColumnTraits Traits { get; }`: What the database type is beyond its .NET type: an enum, a composite, an array, JSON, a column with a default.

### ArxColumnTraits

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxColumnTraits
```

What a column's database type is, beyond its .NET type.

Values:

- `None` = 0: No trait.
- `Enum` = 1: A database enum type: a string is cast to it; read as text.
- `Composite` = 2: A composite (row) type: read as text.
- `Array` = 4: An array of the type.
- `Json` = 8: JSON (`json` or `jsonb`): a string is cast to it.
- `HasDefault` = 16: The database fills it in (identity, default, generated).

## Finding the rows

How Update, Delete and Retrieve find their rows: by id, by a declared key, or by any columns.

### ArxMatch

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxMatch
```

How an update or delete finds its rows: `Id` (the default), `Key` or `Columns`. The values to match come from the entity: its `RecordId` or id attribute for `Id`, the attributes with the key's or columns' names otherwise. Match columns are never written. Immutable.

Created with:

- `ArxMatch.Key(params string[] columns)`: By the declared business key with these columns (in any order). A key the table doesn't declare is refused (ARX1001). On DynamoDB the model declares each entity's key (its partition and sort key attributes), so that key needs no `.Key(...)` of its own there; on the other providers declare it in the schema catalog, so code that moves from DynamoDB adds the `.Key(...)`.
  - `columns`: The columns of a key the table declares, in any order.
- `ArxMatch.Columns(params string[] columns)`: By these columns, declared or not. May match many rows: the call returns how many it changed or deleted.
  - `columns`: Any columns of the table; their values come from the entity's attributes.

Properties:

- `static ArxMatch Id { get; }`: By the table's declared id column (the default). A table declared NoIdColumn can't be matched by id.
- `ArxMatchKind Kind { get; }`: How the rows are found.
- `IReadOnlyList<string> ColumnNames { get; }`: The key's or columns' names, as given; empty for `Id`.

### ArxUpdateOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxUpdateOptions
```

Options for Update and UpdateMultiple.

Properties:

- `ArxMatch Match { get; init; }`: How the rows are found; `Id` by default.
- `bool RequireSingleRow { get; init; }`: When true, every entity must change exactly one row: none is ARX2002 RecordNotFound, more than one is ARX2003 MultipleRecordsMatched, and either way nothing is changed. Off by default: an update by custom columns may change many rows, and the call returns how many.

### ArxDeleteOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxDeleteOptions
```

Options for Delete and DeleteMultiple.

Properties:

- `ArxMatch Match { get; init; }`: How the rows are found; `Id` by default.
- `bool RequireSingleRow { get; init; }`: When true, every entity must delete exactly one row: none is ARX2002 RecordNotFound, more than one is ARX2003 MultipleRecordsMatched, and either way nothing is deleted. Off by default: a delete that finds nothing is a normal outcome, and a delete by custom columns may remove many rows.

### ArxRetrieveOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxRetrieveOptions
```

Options for Retrieve and RetrieveMultiple.

Properties:

- `ArxMatch Match { get; init; }`: How `RetrieveAsync(entity, options)` finds its record: `Id` by default, a declared key, or any columns. More than one matching row is ARX2003 (a Retrieve answers one record). Not used by RetrieveMultiple.
- `ArxColumnSet? Columns { get; init; }`: The columns to read for `RetrieveAsync(entity, options)`; null reads every column.
- `bool LookupNames { get; init; }`: True (the default): a requested lookup column whose referenced table declares a display name reads back with `Name` filled, through one LEFT JOIN per lookup column. False skips the joins.
- `int? CommandTimeout { get; init; }`: Seconds before the query is cancelled (ARX7003). Null keeps the driver's default (30 s in the PostgreSQL, SQL Server and MySQL drivers).

## Queries

RetrieveMultiple's query: what it reads from, which columns, the filters, the joins, the order, paging and aggregates.

### ArxQueryExpression

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public class ArxQueryExpression
```

A query for RetrieveMultiple: what to read from (`Source`: a table, view or function), the columns, the criteria (nested AND/OR), joins (`LinkEntities`), order, paging, distinct and aggregates. Every name in it is validated and quoted by the provider, every value sent as a parameter.

Constructors:

- `new ArxQueryExpression()`: A query with no row source yet: set EntityName or Source.
- `new ArxQueryExpression(string entityName)`: A query on a table or view (optionally schema-qualified: `reporting.v_sales`).
  - `entityName`: The table or view to read (on PostgreSQL also a materialized view), or `schema.name`.
- `new ArxQueryExpression(ArxRowSource source)`: A query on any row source: a table, a view, or a function returning rows (`Function`).
  - `source`: What to read from: a table by name, or a function with its arguments.

Properties:

- `ArxRowSource Source { get; set; }`: What the query reads from.
- `string EntityName { get; set; }`: The row source's name. Setting it makes the source that table or view.
- `bool Distinct { get; set; }`: `SELECT DISTINCT`: rows that differ in no selected column come back once. A distinct (or aggregate) query doesn't add the id to the columns, since it would make every row distinct, so its rows have no `ArxEntity.RecordId`: select the id column if you need it.
- `int? Top { get; set; }`: At most this many rows (`LIMIT`), without paging. Can't be combined with `PageInfo` (ARX1001).
- `ArxColumnSet ColumnSet { get; set; }`: The columns to read. Empty (the default) or `AllColumns` reads every column. A column can be written `column._lk.table.column1,column2` to join a referenced table directly.
- `ArxFilterExpression Criteria { get; set; }`: The conditions rows have to meet (nested And/Or).
- `List<ArxOrderExpression> Orders { get; set; }`: The sort keys, in order; AddOrder adds one.
- `List<ArxLinkEntity> LinkEntities { get; set; }`: The joins; AddLink adds one.
- `ArxPagingInfo? PageInfo { get; set; }`: Offset paging: the page size and number, and whether to return the total (in the same round trip).
- `ArxAggregateInfo? AggregateInfo { get; set; }`: Aggregates and group by; null for a plain read.

Methods:

- `void AddOrder(string attributeName, ArxOrderType orderType)`: Orders the results by an attribute; call again for the next key.
  - `attributeName`: The column to order by.
  - `orderType`: Ascending or Descending.
- `void AddOrder(string entityAlias, string attributeName, ArxOrderType orderType)`: Orders by a column of a joined entity, named by its alias.
  - `entityAlias`: The link alias the column belongs to.
  - `attributeName`: The column to order by.
  - `orderType`: Ascending or Descending.
- `ArxLinkEntity AddLink(string linkToEntityName, string linkFromAttributeName, string linkToAttributeName, ArxJoinOperator joinOperator)`: Joins a table (see `ArxLinkEntity`) and returns the join, to add its columns, alias and criteria.
  - `linkToEntityName`: The table to join.
  - `linkFromAttributeName`: The column of the query's own table that the join matches.
  - `linkToAttributeName`: The column of the joined table that it matches.
  - `joinOperator`: INNER (rows with a match only) or LEFT (every row, with nulls where nothing matches).

### ArxRowSource

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxRowSource
```

What a query reads from: a table or view by name, or a function that returns rows, with its arguments. Immutable: `Returns` and `AllowWrites` return a new source.

Created with:

- `ArxRowSource.Table(string name)`: A table or view (on PostgreSQL also a materialized view or foreign table).
  - `name`: The table or view (on PostgreSQL also a materialized view or foreign table), or `schema.name`.
- `ArxRowSource.Function(string name)`: A function with no arguments.
  - `name`: The function, or `schema.function`.
- `ArxRowSource.Function(string name, params (string Name, object? Value)[] arguments)`: A function with named arguments: `Function("fn", ("p_region", "NL"), ("p_active", true))`.
  - `name`: The function, or `schema.function`.
  - `arguments`: Each argument by its parameter's name, with its value.
- `ArxRowSource.Function(string name, params object?[] arguments)`: A function with positional arguments: `Function("fn", "NL", true)`.
  - `name`: The function, or `schema.function`.
  - `arguments`: The arguments, in the function's parameter order.

Properties:

- `ArxRowSourceKind Kind { get; }`: A table (anything read by name) or a function called with arguments.
- `string Name { get; }`: The table, view or function name, optionally schema-qualified (`reporting.v_sales`). Validated by the provider.
- `IReadOnlyList<ArxFunctionArgument> Arguments { get; }`: The function's arguments, in order. Empty for a table.
- `IReadOnlyList<ArxResultColumn> ResultColumns { get; }`: The declared result columns of a function returning untyped rows; empty otherwise.
- `bool AllowsWrites { get; }`: False (the default): a function is read in a read-only transaction when ARX owns the connection, so a function that writes is refused. Inside an `ArxTransaction`, a batch scope or a connection the caller passes in, the read runs in that transaction as it is: a function that writes does write there, since ARX can't make the caller's transaction read-only. True after `AllowWrites`.
- `bool IsFunction { get; }`: True for a function row source.

Methods:

- `ArxRowSource Returns(params (string Name, Type Type)[] columns)`: Declares the result columns of a function that returns untyped rows (`RETURNS SETOF record`).
  - `columns`: The function's result columns and their .NET types, in order.
- `ArxRowSource AllowWrites()`: Lets a function read change data: no read-only transaction around it. Use only for functions you trust.

### ArxColumnSet

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public class ArxColumnSet
```

The columns a read returns: `new ArxColumnSet("name", "email")`, or `All` for all of them. The declared id is always read, so the record's RecordId is set.

Constructors:

- `new ArxColumnSet()`: No columns yet: add them with AddColumn or AddColumns. A read with no columns returns every column (unlike Dynamics XRM, where an empty ColumnSet reads only the id).
- `new ArxColumnSet(params string[] columns)`: These columns: `new ArxColumnSet("name", "email")`.
  - `columns`: The column names, in the order to read them.

Properties:

- `static ArxColumnSet All { get; }`: Every column of the row source: a new set each time, so changing one never changes another. It replaces the constructor that took a bool, removed in 1.0.0-rc.1: its `false` read every column too, unlike XRM's `ColumnSet(false)`. An empty `new ArxColumnSet()` also reads every column; to read only the id, name it: `new ArxColumnSet("id")`.
- `bool AllColumns { get; set; }`: True to read every column of the row source.
- `List<string> Columns { get; }`: The columns to read, by name.

Methods:

- `void AddColumn(string column)`: Adds an attribute to read.
  - `column`: The column to read.
- `void AddColumns(params string[] columns)`: Adds attributes to read.
  - `columns`: The columns to read.

### ArxFilterExpression

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxFilterExpression
```

A group of conditions joined by And or Or (`FilterOperator`), with nested groups (`Filters`) for any mix of the two: a query's `Criteria` and a link entity's `LinkCriteria`.

Constructors:

- `new ArxFilterExpression()`: An empty filter whose conditions all have to hold (And).
- `new ArxFilterExpression(ArxLogicalOperator filterOperator)`: An empty filter joining its conditions with And or Or.
  - `filterOperator`: And: every condition has to hold. Or: any of them.

Properties:

- `List<ArxConditionExpression> Conditions { get; set; }`: The filter's conditions.
- `ArxLogicalOperator FilterOperator { get; set; }`: How the conditions and nested filters are joined: And or Or.
- `List<ArxFilterExpression> Filters { get; set; }`: Nested filters, each joined with the conditions by FilterOperator: `a AND (b OR c)`.

Methods:

- `void AddCondition(ArxConditionExpression condition)`: Adds a condition to this filter.
  - `condition`: The condition to add.
- `void AddCondition(string attributeName, ArxConditionOperator conditionOperator, params object[] values)`: Adds a condition on an attribute of the query's entity: the attribute, the operator and its values.
  - `attributeName`: The column to compare (`alias.column` for a link's).
  - `conditionOperator`: How to compare: Equal, In, Between, Contains, Null and the others.
  - `values`: The values to compare with, sent as parameters: one for most operators, several for In, two for Between, none for Null and NotNull.
- `void AddCondition(string entityName, string attributeName, ArxConditionOperator conditionOperator, params object[] values)`: Adds a condition on an attribute of a linked entity, named by its alias.
  - `entityName`: The link alias (or table) the column belongs to; the query's own table when empty.
  - `attributeName`: The column to compare (`alias.column` for a link's).
  - `conditionOperator`: How to compare: Equal, In, Between, Contains, Null and the others.
  - `values`: The values to compare with, sent as parameters: one for most operators, several for In, two for Between, none for Null and NotNull.
- `void AddFilter(ArxFilterExpression childFilter)`: Adds a nested filter, combined with this one's conditions by this filter's operator.
  - `childFilter`: The nested filter to add.
- `ArxFilterExpression AddFilter(ArxLogicalOperator logicalOperator)`: Adds an empty nested filter with this operator and returns it, to add conditions to.
  - `logicalOperator`: How the nested filter joins its conditions: And or Or.

### ArxConditionExpression

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxConditionExpression
```

One condition: an attribute, an operator (`ArxConditionOperator`) and its values. Every value is sent as a parameter, never written into the SQL.

Constructors:

- `new ArxConditionExpression()`: An empty condition; set its attribute, operator and values.
- `new ArxConditionExpression(string attributeName, ArxConditionOperator conditionOperator)`: A condition with no value: Null and NotNull.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
- `new ArxConditionExpression(string attributeName, ArxConditionOperator conditionOperator, List<object> values)`: A condition with a list of values: In, NotIn, Between.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
  - `values`: The values compared with, each sent as a parameter.
- `new ArxConditionExpression(string attributeName, ArxConditionOperator conditionOperator, object value)`: A condition with one value.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
  - `value`: The value compared with, sent as a parameter.
- `new ArxConditionExpression(string attributeName, ArxConditionOperator conditionOperator, params object[] values)`: A condition with its values.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
  - `values`: The values compared with, each sent as a parameter.
- `new ArxConditionExpression(string entityName, string attributeName, ArxConditionOperator conditionOperator)`: A condition with no value on a joined entity's column.
  - `entityName`: The alias of the link entity whose column is compared.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
- `new ArxConditionExpression(string entityName, string attributeName, ArxConditionOperator conditionOperator, object value)`: A condition with one value on a joined entity's column.
  - `entityName`: The alias of the link entity whose column is compared.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
  - `value`: The value compared with, sent as a parameter.
- `new ArxConditionExpression(string entityName, string attributeName, ArxConditionOperator conditionOperator, params object[] values)`: A condition with its values on a joined entity's column.
  - `entityName`: The alias of the link entity whose column is compared.
  - `attributeName`: The column compared.
  - `conditionOperator`: How the column is compared with the values.
  - `values`: The values compared with, each sent as a parameter.

Properties:

- `string EntityName { get; set; }`: The alias of the link entity whose column is compared; null for the filter's own row source.
- `string AttributeName { get; set; }`: The column compared.
- `ArxConditionOperator Operator { get; set; }`: How the column is compared with the values.
- `List<object> Values { get; set; }`: The values compared with; each is sent as a parameter.

### ArxConditionOperator

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxConditionOperator
```

How a condition compares its attribute with its values. Contains, BeginsWith and EndsWith (and their negations) treat `%` and `_` as plain characters. Whether they ignore case depends on the database: PostgreSQL and MongoDB ignore it; on SQL Server and MySQL the column's collation decides (the default ignores it; a binary or case-sensitive collation such as `utf8mb4_bin` doesn't); DynamoDB compares case-sensitively and only when asked (`CaseSensitivePatterns`).

Values:

- `Equal` = 0: The attribute equals the value.
- `NotEqual` = 1: The attribute differs from the value; never matches a null or a missing attribute.
- `GreaterThan` = 2: The attribute is greater than the value.
- `LessThan` = 3: The attribute is less than the value.
- `GreaterEqual` = 4: The attribute is greater than or equal to the value.
- `LessEqual` = 5: The attribute is less than or equal to the value.
- `Like` = 6: The attribute matches a pattern (`%` any text, `_` one character); where a provider can't, ARX8001.
- `NotLike` = 7: The attribute doesn't match the pattern.
- `In` = 8: The attribute equals one of the values.
- `NotIn` = 9: The attribute equals none of the values.
- `Between` = 10: The attribute is between the two values, both included.
- `NotBetween` = 11: The attribute is outside the two values.
- `Null` = 12: The attribute is null (or, where documents may omit it, missing).
- `NotNull` = 13: The attribute has a value.
- `Contains` = 49: The attribute contains the text (the value is text, never a pattern).
- `DoesNotContain` = 50: The attribute doesn't contain the text.
- `BeginsWith` = 54: The attribute begins with the text.
- `DoesNotBeginWith` = 55: The attribute doesn't begin with the text.
- `EndsWith` = 56: The attribute ends with the text.
- `DoesNotEndWith` = 57: The attribute doesn't end with the text.

### ArxLogicalOperator

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxLogicalOperator
```

How a filter joins its conditions and nested filters: all of them (And) or any of them (Or).

Values:

- `And` = 0: Every condition must hold.
- `Or` = 1: Any condition may hold.

### ArxDateTimeConditionOption

class in `ARX.SDK.Models`, package `ARX.SDK`.

```csharp
public class ArxDateTimeConditionOption
```

A date and time condition value that says how to compare: the date only (the default) or the date and the time.

Constructors:

- `new ArxDateTimeConditionOption()`: A value compared by its date only, until ComparingType says otherwise.

Properties:

- `DateTime Value { get; set; }`: The date and time to compare with.
- `ArxDateTimeConditionOptionType ComparingType { get; set; }`: DateOnly (the default) compares the column's date with this date; DateAndTime compares the full value.

### ArxDateTimeConditionOptionType

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxDateTimeConditionOptionType
```

Whether a date and time condition compares the date only or the date and the time.

Values:

- `DateAndTime`: 
- `DateOnly`: 

### ArxLinkEntity

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public class ArxLinkEntity
```

A join from a query's row source (or from another link) to another table: the column on each side, the join (`JoinOperator`), an alias, the columns it returns (read back as `alias.column`) and its own criteria.

Constructors:

- `new ArxLinkEntity()`: An empty link; set its tables, columns and join.
- `new ArxLinkEntity(string linkToEntityName, string linkFromAttributeName, string linkToAttributeName, ArxJoinOperator joinOperator)`: A join to another table: `JOIN linkTo ON linkTo.linkToAttribute = from.linkFromAttribute`.
  - `linkToEntityName`: The table joined.
  - `linkFromAttributeName`: The column on the query's side (or the parent link's).
  - `linkToAttributeName`: The column on the joined table.
  - `joinOperator`: INNER, LEFT or RIGHT; DEFAULT joins as INNER.

Properties:

- `string LinkFromAttributeName { get; set; }`: The column on the query's side (or the parent link's) that the join matches.
- `string? LinkFromEntityName { get; set; }`: The table on the query's side; informational, the join starts from the query or the parent link.
- `string LinkToEntityName { get; set; }`: The table joined.
- `string LinkToAttributeName { get; set; }`: The column on the joined table that the join matches.
- `ArxColumnSet ColumnSet { get; set; }`: The joined table's columns to read, returned as `alias.column`.
- `string? EntityAlias { get; set; }`: The join's alias: the prefix of its columns in the result, and the name conditions and orders use for it.
- `ArxFilterExpression LinkCriteria { get; set; }`: Conditions on the joined table, applied in the join itself (a LEFT join keeps rows with no match).
- `ArxJoinOperator JoinOperator { get; set; }`: INNER, LEFT or RIGHT; DEFAULT joins as INNER.
- `List<ArxLinkEntity> LinkEntities { get; set; }`: Further joins from this joined table.

### ArxJoinOperator

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxJoinOperator
```

The join a link entity makes: `Inner`, `Left` or `Right`. `Default` joins as `Inner`. (Named INNER, LEFT, RIGHT and DEFAULT before 1.0.0-rc.1.)

Values:

- `Default`: No join kind given: an inner join.
- `Inner`: Only rows that have a match in the linked table.
- `Left`: Every row of the query's table, with the linked table's columns null where nothing matches.
- `Right`: Every row of the linked table, with the query's columns null where nothing matches (not on MongoDB).

### ArxOrderExpression

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public class ArxOrderExpression
```

One sort key of a query: an attribute, ascending or descending, of the main row source or of a joined entity (`FromEntityAlias`).

Constructors:

- `new ArxOrderExpression()`: An ascending order with no attribute yet.
- `new ArxOrderExpression(string attributeName, ArxOrderType orderType)`: An order by this attribute, ascending or descending.
  - `attributeName`: The column, or an aggregate column's alias, to sort by.
  - `orderType`: Ascending or descending.

Properties:

- `string? FromEntityAlias { get; set; }`: The alias of the joined entity the attribute belongs to; null (the default) for the main row source.
- `string AttributeName { get; set; }`: The column, or an aggregate column's alias, to sort by.
- `ArxOrderType OrderType { get; set; }`: Ascending or descending.

### ArxOrderType

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxOrderType
```

Ascending or descending.

Values:

- `Ascending` = 0: Smallest first.
- `Descending` = 1: Largest first.

### ArxPagingInfo

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public class ArxPagingInfo
```

Paging for RetrieveMultiple: the page size (`Count`, 5,000 by default) and the 1-based page number. The total is opt-in (`ReturnTotalRecordCount`): it counts every matching row, a second statement in the same round trip.

Constructors:

- `new ArxPagingInfo()`: Page 1 of 5,000 rows, without the total.

Properties:

- `int Count { get; set; }`: The page size: at most this many rows per page.
- `int PageNumber { get; set; }`: The page to read, from 1.
- `bool ReturnTotalRecordCount { get; set; }`: True to count every matching row as well (TotalRecordCount, TotalPageCount): a second statement in the same round trip. Leave it off when the screen doesn't show the total.
- `string? PagingCookie { get; set; }`: Token paging: the `ArxEntityCollection.PagingCookie` of the previous page, to read the page after it; null (the default) for the first page. The cookie is opaque, written by the provider that read the previous page, for the same query: never build or change one. With a cookie, leave `PageNumber` at 1. Only providers that declare `ArxCapability.TokenPaging` accept it; the others refuse it (ARX8001 NotSupported) rather than ignore it.

Methods:

- `ArxPagingInfo? Next(Services.ArxEntityCollection page)`: The paging that reads the page after `page`, on any provider: by its cookie where the provider returned one (MongoDB, DynamoDB), by the next page number where it didn't (PostgreSQL, SQL Server, MySQL); null when no page follows. Same page size; the total isn't asked for again. A loop that only passes the cookie on reads the first page again on a provider without cookies, so a loop meant to run everywhere ends each page with `query.PageInfo = query.PageInfo.Next(page)` and stops on null.
  - `page`: The page the query with this paging returned.

### ArxAggregateInfo

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public class ArxAggregateInfo
```

Aggregates and group by for RetrieveMultiple: each aggregate column has an alias, an attribute and an operator (`ArxAggregateOperator`); the group-by columns are listed apart.

Constructors:

- `new ArxAggregateInfo()`: An empty aggregate: add columns with AddAggregateColumn and group-by columns with AddGroupByColumn.

Properties:

- `List<ArxAggregateColumn> AggregateColumns { get; set; }`: The aggregate columns: each has an alias (its name in the result), an attribute and an operator.
- `List<string> GroupByColumns { get; set; }`: The columns the rows are grouped by. Each one is also returned in the result.

Methods:

- `void AddAggregateColumn(ArxAggregateColumn column)`: Adds an aggregate column (an alias, the attribute and the operator).
  - `column`: The aggregate: its alias, column and operator.
- `void AddAggregateColumn(string aliasName, string attributeName, ArxAggregateOperator aggregateOperator)`: Adds an aggregate column: `aliasName` is the name the result holds the value under.
  - `aliasName`: The attribute the result is read into, on each group's record.
  - `attributeName`: The column to aggregate (`alias.column` for a link's); empty for a Count of rows.
  - `aggregateOperator`: The aggregate: Count, CountDistinct, Sum, Avg, Min, Max and the others.
- `void AddGroupByColumn(string column)`: Groups the aggregates by this attribute.
  - `column`: The column to group by (`alias.column` for a link's); each group's record carries it.
- `void AddGroupByColumns(params string[] columns)`: Groups the aggregates by these attributes, in order.
  - `columns`: The columns to group by, in order (`alias.column` for a link's).

### ArxAggregateOperator

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxAggregateOperator
```

The value an aggregate column computes: a count, the minimum, maximum, sum or average, a standard deviation or a variance.

Values:

- `None` = 0: No aggregate.
- `Count` = 1: The number of rows (or of non-null values of the attribute).
- `CountDistinct` = 2: The number of distinct non-null values.
- `CountBig` = 3: As Count, as a 64-bit number where the database distinguishes it.
- `CountBigDistinct` = 4: As CountDistinct, as a 64-bit number where the database distinguishes it.
- `Min` = 5: The smallest value.
- `Max` = 6: The largest value.
- `Sum` = 7: The sum of the values.
- `Avg` = 8: The average of the values.
- `StDev` = 9: The sample standard deviation.
- `StDevP` = 10: The population standard deviation.
- `Var` = 11: The sample variance.
- `VarP` = 12: The population variance.

## Procedures and functions

Execute: a call to a stored procedure or function, its parameters and paging, and what comes back.

### ArxProcedureExpression

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxProcedureExpression
```

A call to a routine the database owns: a stored procedure or a function, with its parameters, in the pattern of `ArxQueryExpression`. Never SQL text.

Constructors:

- `new ArxProcedureExpression()`: A call with no routine yet: set ProcedureName.
- `new ArxProcedureExpression(string procedureName)`: A call to this procedure; set ProcedureType to call a function.
  - `procedureName`: The routine, or `schema.routine`.

Properties:

- `string ProcedureName { get; set; }`: The routine's name, optionally schema-qualified (`reporting.sp_close_month`). Validated by the provider.
- `ArxProcedureType ProcedureType { get; set; }`: Procedure (the default) or function.
- `List<ArxProcedureParameter> Parameters { get; set; }`: The parameters, in the order they are passed.
- `bool ReturnsCursors { get; set; }`: A function that returns `refcursor` or `SETOF refcursor`: each cursor is read as a result set. A procedure declares its cursors as parameters instead.
- `List<ArxOrderExpression> Orders { get; set; }`: The order of a function's rows when ARX pages them (way 2). Not for procedures.
- `ArxPagingInfo? PageInfo { get; set; }`: The page to return: of a function's rows, of a cursor, or through the routine's own paging arguments (`PagingParameters`).
- `ArxPagingParameters? PagingParameters { get; set; }`: The routine pages itself: ARX fills these arguments from `PageInfo` (way 1).
- `string? PagedResultSet { get; set; }`: Which result set `PageInfo` pages when there are several cursors: a cursor parameter's name. The first by default.

Methods:

- `void AddParameter(string name, object? value)`: A named IN argument.
  - `name`: The routine's parameter name, as the database declares it.
  - `value`: The value, sent as a parameter; null for SQL NULL.
- `void AddParameter(object? value)`: A positional IN argument (positional arguments come before named ones).
  - `value`: The value, sent as a parameter; null for SQL NULL.
- `void AddParameter(string name, Type type, object? value)`: A named IN argument with its type, for a null the database can't type by itself (an overloaded routine).
  - `name`: The routine's parameter name, as the database declares it.
  - `type`: The parameter's .NET type, so a null is sent with the right database type.
  - `value`: The value, sent as a parameter; null for SQL NULL.
- `void AddOutParameter<T>(string name)`: An OUT parameter of a procedure, read into `Outputs[name]` as `T`.
  - `name`: The routine's OUT parameter name; its value is read back into the result's `Outputs`.
- `void AddOutParameter(string name, Type type)`: An OUT parameter of a procedure, read into `Outputs[name]` as `type`.
  - `name`: The routine's OUT parameter name; its value is read back into the result's `Outputs`.
  - `type`: The .NET type the value is read as.
- `void AddInOutParameter<T>(string name, T value)`: An INOUT parameter: `value` goes in, the procedure's value is read into `Outputs[name]`.
  - `name`: The routine's INOUT parameter name; the value it ends with is read back.
  - `value`: The value sent in.
- `void AddCursorParameter(string name)`: A table the procedure returns, through an `INOUT refcursor` parameter: read into `ResultSets[name]`.
  - `name`: The parameter through which the procedure returns a table (a refcursor on PostgreSQL), read as a result set.
- `void AddVariadicParameter(string name, Array values)`: An array passed to a named `VARIADIC` parameter.
  - `name`: The routine's VARIADIC parameter name.
  - `values`: The values, sent as one array.
- `void AddVariadicParameter(Array values)`: An array passed to a positional `VARIADIC` parameter.
  - `values`: The values, sent as one array.
- `void AddOrder(string attributeName, ArxOrderType orderType)`: Orders a function's rows (way 2).
  - `attributeName`: The result column to order by.
  - `orderType`: Ascending or Descending.

### ArxProcedureType

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxProcedureType
```

What a routine is: PostgreSQL calls them differently (`CALL` against `SELECT`), so the caller says which.

Values:

- `Procedure`: A stored procedure: `CALL name(...)`. Returns OUT values and, through cursor parameters, tables.
- `Function`: A function: `SELECT * FROM name(...)`. Returns rows (a value, a row of OUT values, a table, a set).

### ArxProcedureParameter

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxProcedureParameter
```

One parameter of a routine: by name or by position (`Name` null), with its value and, when needed, its type.

Constructors:

- `new ArxProcedureParameter(string? name, object? value, Type? type, ArxProcedureParameterDirection direction)`: A parameter; the AddParameter methods of ArxProcedureExpression create them.
  - `name`: The parameter's name in the routine; null to pass it by position.
  - `value`: The value passed in (null for an OUT parameter).
  - `type`: Its .NET type, when the value alone doesn't say (a null, an OUT or INOUT parameter).
  - `direction`: In, Out, InOut, a cursor or a variadic list.

Properties:

- `string? Name { get; }`: The parameter's name in the routine; null for a positional argument.
- `object? Value { get; }`: The value passed in (null for OUT and cursor parameters). Sent as a typed parameter, like a write's value.
- `Type? Type { get; }`: The declared .NET type: required for OUT and INOUT, and for a null the database must type; null otherwise.
- `ArxProcedureParameterDirection Direction { get; }`: In, Out, InOut, a cursor or a variadic list.

### ArxProcedureParameterDirection

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxProcedureParameterDirection
```

How a parameter of a routine is passed.

Values:

- `In`: A value passed in.
- `Out`: A value the procedure sets: declared with its type, read into `Outputs`.
- `InOut`: A value passed in and read back, possibly changed.
- `Cursor`: A table the procedure returns: an `INOUT refcursor`, read as a result set named after the parameter.
- `Variadic`: An array passed to a `VARIADIC` parameter.

### ArxPagingParameters

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxPagingParameters
```

The arguments of a routine that pages itself (way 1): ARX fills them from `PageInfo`, and reads the total from `TotalRecordCount` (an OUT parameter of a procedure, a result column of a function).

Created with:

- `ArxPagingParameters.PageNumber(string pageNumber, string pageSize, string? totalRecordCount = null)`: The routine takes a page number (from 1) and a page size: `PageNumber("p_page", "p_page_size", totalRecordCount: "p_total")`.
  - `pageNumber`: The routine's page number parameter.
  - `pageSize`: The routine's page size parameter.
  - `totalRecordCount`: Where the routine returns the total: an OUT parameter of a procedure, or a result column of a function. Null when it doesn't.
- `ArxPagingParameters.OffsetLimit(string offset, string limit, string? totalRecordCount = null)`: The routine takes an offset and a limit: `OffsetLimit("p_offset", "p_limit", totalRecordCount: "p_total")`.
  - `offset`: The routine's offset parameter (rows to skip).
  - `limit`: The routine's limit parameter (rows to return).
  - `totalRecordCount`: Where the routine returns the total: an OUT parameter of a procedure, or a result column of a function. Null when it doesn't.

Properties:

- `ArxPagingParametersStyle Style { get; }`: Whether the routine takes a page number and size, or an offset and a limit.
- `string First { get; }`: The page number's parameter (PageNumber style) or the offset's (OffsetLimit style).
- `string Second { get; }`: The page size's parameter (PageNumber style) or the limit's (OffsetLimit style).
- `string? TotalRecordCount { get; }`: Where the routine returns the total: a procedure's OUT parameter (ARX declares it as `bigint` if it isn't), or a function's result column. Null when the routine returns none.

### ArxExecuteOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxExecuteOptions
```

Options for one Execute call.

Properties:

- `int? CommandTimeout { get; init; }`: The command timeout in seconds for this call; null keeps the driver's default (30 s in the PostgreSQL, SQL Server and MySQL drivers). Long jobs set it.
- `bool CollectMessages { get; init; }`: True (the default): the messages the routine sends while it runs (notices, warnings) are collected into `Messages`. Never logged.

### ArxExecuteResult

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxExecuteResult
```

What a routine returned: its OUT and INOUT values, its result sets (a procedure's tables, a function's rows) and the messages it sent. No rows-affected count: not every database reports one for a call.

Constructors:

- `new ArxExecuteResult(string routineName)`: An empty result for a call to this routine; the provider fills it.
  - `routineName`: The routine's name, which is also the name of the Outputs entity.

Properties:

- `const string MessagesKey`: The key under which a failed call's messages are put in `Data`.
- `ArxEntity Outputs { get; }`: The OUT and INOUT values of a procedure, one attribute per parameter name.
- `ArxResultSetCollection ResultSets { get; }`: The tables a procedure returned (by its cursor parameters' names) or a function's rows (`ResultSets[0]`).
- `IReadOnlyList<ArxDatabaseMessage> Messages { get; }`: The messages the routine sent while it ran, in order (when `CollectMessages`).

Methods:

- `void AddMessage(ArxDatabaseMessage message)`: Adds a message (providers).
  - `message`: A message the routine raised (a notice or warning).
- `T? Value<T>()`: A function's single value: the one column of its one row, converted to `T`. Default when there is no row or the value is NULL; ARX2003 when there are several rows; ARX1001 when the row has several columns or the value isn't a `T`.

### ArxResultSetCollection

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxResultSetCollection : IReadOnlyList<ArxEntityCollection>
```

The result sets of a call, in order, also by name (a cursor parameter's name, or the cursor's).

Properties:

- `int Count { get; }`: How many result sets the call returned.
- `ArxEntityCollection this[int index] { get; }`: The result set at this position, in the order the call returned them.
- `ArxEntityCollection this[string name] { get; }`: The result set with this name (case-insensitive). ARX1001 if there is none.

Methods:

- `bool TryGet(string name, out ArxEntityCollection set)`: Gets a result set by name; false when there is none.
  - `name`: The result set's name: its cursor parameter's name.
  - `set`: The result set when found; otherwise null.
- `void Add(ArxEntityCollection set)`: Adds a result set (providers).
  - `set`: The result set to add.
- `IEnumerator<ArxEntityCollection> GetEnumerator()`: The result sets, in the order the routine returned them.

### ArxDatabaseMessage

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxDatabaseMessage
```

A message a routine sent while it ran (PostgreSQL `RAISE NOTICE`, SQL Server `PRINT`, MySQL warnings), in the order sent.

Constructors:

- `new ArxDatabaseMessage(string severity, string sqlState, string text, string? detail, string? hint)`: A message, as the provider reads it from the database.
  - `severity`: NOTICE, WARNING, INFO, LOG or DEBUG.
  - `sqlState`: The message's SQLSTATE code.
  - `text`: The message text.
  - `detail`: Its detail, or null.
  - `hint`: Its hint, or null.

Properties:

- `string Severity { get; }`: NOTICE, WARNING, INFO, LOG or DEBUG.
- `string SqlState { get; }`: The message's SQLSTATE code (00000 for a plain notice).
- `string Text { get; }`: The message text.
- `string? Detail { get; }`: The message's detail, when the routine gave one.
- `string? Hint { get; }`: The message's hint, when the routine gave one.

## Errors

What ARX throws: refused before the database, refused by it, or not supported; each with a stable code.

### ArxException

class in `ARX.SDK`, package `ARX.SDK`.

```csharp
public class ArxException : Exception
```

Base type of every error ARX.SDK reports, apart from `ArgumentNullException` for null arguments. Handle errors by `Code`, `Category` or `IsTransient`, which are the same in every provider; the native details (`NativeCode`, `SqlState`, `InnerException`) are kept for diagnostics. Messages contain codes and names, never attribute values.

Constructors:

- `new ArxException(ArxErrorCode code, string message, Exception? innerException = null)`: An ARX error with its code and a message for logs and developers.
  - `code`: The ARX error code: its thousands digit is the category.
  - `message`: A message for logs and developers. It names tables, columns and constraints, never values.
  - `innerException`: The error that caused it, if any.

Properties:

- `ArxErrorCode Code { get; }`: The stable ARX error code.
- `ArxErrorCategory Category { get; }`: The category of `Code`.
- `bool IsTransient { get; init; }`: True when repeating the whole operation can succeed (deadlocks, timeouts, connection drops).
- `string? Provider { get; init; }`: The provider that reported the error, for example "PostgreSql". Null for errors raised before any provider work.
- `string? EntityName { get; init; }`: The entity (table or collection) involved, when known.
- `string? AttributeName { get; init; }`: The attribute (column) involved, when known.
- `string? ConstraintName { get; init; }`: The constraint the database reported, when known.
- `string? NativeCode { get; init; }`: The provider's own error code, for example "23505", "2627", "E11000" or an AWS exception name.
- `string? SqlState { get; init; }`: The ISO SQLSTATE, when the database supplies one.
- `string? Detail { get; init; }`: The database's detail for the error, when it gives one (a routine's `RAISE ... USING DETAIL`).
- `string? Hint { get; init; }`: The database's hint for the error, when it gives one (a routine's `RAISE ... USING HINT`).
- `int? BatchNumber { get; }`: The 1-based number of the failed call within its batch scope; null for errors raised outside a scope. Set by the scope when the error passes through it.

Methods:

- `static string FormatCode(ArxErrorCode code)`: The message prefix for a code, for example "ARX3001 UniqueViolation".
  - `code`: The error code.

### ArxValidationException

class in `ARX.SDK`, package `ARX.SDK`.

```csharp
public sealed class ArxValidationException : ArxException
```

The caller's input is invalid. Always raised before any database access.

Constructors:

- `new ArxValidationException(ArxErrorCode code, string message, Exception? innerException = null)`: A request refused before anything was sent to the database.
  - `code`: The ARX error code: its thousands digit is the category.
  - `message`: A message for logs and developers. It names tables, columns and constraints, never values.
  - `innerException`: The error that caused it, if any.

### ArxDatabaseException

class in `ARX.SDK`, package `ARX.SDK`.

```csharp
public sealed class ArxDatabaseException : ArxException
```

The database reported an error. The native exception is the `InnerException`.

Constructors:

- `new ArxDatabaseException(ArxErrorCode code, string message, Exception innerException)`: A database error mapped to its ARX code; the driver's exception is the inner exception.
  - `code`: The ARX error code: its thousands digit is the category.
  - `message`: A message for logs and developers. It names tables, columns and constraints, never values.
  - `innerException`: The driver's exception (PostgresException, SqlException, MySqlException, a MongoException or an AmazonDynamoDBException).

Methods:

- `static ArxException InLinkWhenItIs(ArxException mapped, ARX.SDK.Query.ArxQueryExpression query)`: For the providers' use: an ARX5002 UndefinedAttribute from a query whose missing column only its link entities name, said of the link's table (`EntityName`) and alias instead of the query's own table. Any other error is returned as it is.
  - `mapped`: The error the provider's mapper made, with the missing column as its `AttributeName`.
  - `query`: The query that was sent.

### ArxNotSupportedException

class in `ARX.SDK`, package `ARX.SDK`.

```csharp
public sealed class ArxNotSupportedException : ArxException
```

The provider doesn't support the requested operation or feature.

Constructors:

- `new ArxNotSupportedException(string message, Exception? innerException = null)`: Something the provider can't do (ARX8001), refused rather than ignored.
  - `message`: A message for logs and developers. It names tables, columns and constraints, never values.
  - `innerException`: The error that caused it, if any.

### ArxErrorCode

enum in `ARX.SDK`, package `ARX.SDK`.

```csharp
public enum ArxErrorCode
```

Stable ARX error codes, identical in every provider and language. The thousands digit is the category. Numbers are never reused or renumbered; names are the cross-language identifiers.

Values:

- `InvalidArgument` = 1001: Invalid input not covered by a more specific code.
- `MissingEntityName` = 1002: The entity name is null or blank.
- `InvalidIdentifier` = 1003: An entity or attribute name fails the identifier rules.
- `DuplicateAttribute` = 1004: The same attribute appears more than once (names are case-insensitive).
- `InvalidLookup` = 1005: A lookup (`ArxEntityReference`) has no usable Id.
- `InvalidSelectionSet` = 1006: A selection set value has no option set name.
- `UnsupportedValueType` = 1007: An attribute value has a type the provider can't write.
- `InvalidConnection` = 1008: The connection or transaction is of the wrong driver type, or the service has no connection string.
- `TransactionMismatch` = 1009: The transaction belongs to a different connection.
- `TransactionCompleted` = 1010: The transaction has already been committed, rolled back or disposed.
- `SelectionSetValueNotAllowed` = 1011: A selection set value isn't allowed by its set in the catalog: not one of its options, of the wrong kind, a retired option, several values for a single-choice set, a duplicate, or a value the set's storage can't hold.
- `UnknownSelectionSet` = 1012: A selection set value names a set that isn't in the catalog, or no catalog was supplied.
- `InvalidDateTimeValue` = 1013: A date or time value that would be stored as something else than the caller meant: default(DateTime), default(DateTimeOffset) or default(DateOnly) (no real date: a database would store a sentinel or refuse it), or an array mixing UTC and Unspecified DateTime values.
- `BatchScopeBusy` = 1014: A batch scope was called while another call on it was still running. A scope holds one connection, which runs one command at a time: await each call before the next.
- `TransactionAborted` = 1015: A call or a commit on a transaction that an earlier failed call has aborted. The database has already discarded the transaction's work; it can only be rolled back.
- `IdNotDeclared` = 1016: The entity's table isn't declared in the service's schema catalog, and the entity doesn't declare its own id column. A service with a catalog uses only what is declared: ARX doesn't guess an id column. A service created without a catalog reads the table's primary key instead (where the provider can), and raises `TableNotResolvable` when it can't.
- `SuspectedInjection` = 1017: A name (entity, attribute, match column or type) contains SQL syntax: a quote, a statement separator, a comment marker, a bracket, an operator or an SQL keyword after a space. That is the shape of an SQL injection attempt, not of a typo, so it gets its own code to alert on. Refused before the database: nothing was sent. Values are never checked for this: they are always parameters, and any text is stored as typed.
- `NotPreloaded` = 1018: The service is `Strict` and the call names a table or column that wasn't preloaded: refused before the database. Preload it, or turn Strict off.
- `TableNotResolvable` = 1019: A service without a schema catalog resolves each table from the database, and this table has no id the call can use: no primary key, a primary key of several columns, or one of a type ARX can't use as an id. Refused before anything is sent, only for a call that needs the id (Create, Retrieve, Update or Delete by id). Declare the table in a schema catalog (`ArxIdColumn.NoIdColumn`), or match by a key or columns.
- `RecordNotFound` = 2002: The record addressed by key doesn't exist.
- `MultipleRecordsMatched` = 2003: An update or delete with `RequireSingleRow` found more than one row for an entity. Nothing was changed.
- `RecordChanged` = 2004: The record was changed since it was read: an Update or Delete carried a version (optimistic concurrency) that isn't the record's any more. Nothing was changed: read it again, and apply the change to what is there now.
- `UniqueViolation` = 3001: A unique constraint or key was violated.
- `ForeignKeyViolation` = 3002: A referenced record is missing, or a record is still referenced.
- `NotNullViolation` = 3003: A required attribute has no value.
- `CheckViolation` = 3004: A check constraint or validation rule failed.
- `RaisedByDatabase` = 3005: A routine the database runs (a procedure or function) refused the call on purpose (PostgreSQL `RAISE EXCEPTION`, SQL Server `THROW`, MySQL `SIGNAL`). On PostgreSQL: `RAISE EXCEPTION` (SQLSTATE P0001), an `ASSERT` or a state of the routine's own (`USING ERRCODE = 'AX001'`). The message is the routine's; `SqlState`, `Detail` and `Hint` are its own.
- `ValueOutOfRange` = 4001: A number is outside the column's range.
- `ValueTooLong` = 4002: Text or binary data is longer than the column allows.
- `InvalidValueFormat` = 4003: A value can't be parsed for its column (for example invalid JSON, dates or encoding).
- `DataTypeMismatch` = 4004: A value's type doesn't fit the column.
- `UndefinedEntity` = 5001: The table or collection doesn't exist.
- `UndefinedAttribute` = 5002: The column doesn't exist or can't be written.
- `SchemaMismatch` = 5003: A declaration in the schema catalog doesn't match the table: the database returned an id of another type, or `ValidateSchemaAsync` found a difference. The exception says whether rows were stored.
- `PermissionDenied` = 6001: The database user lacks the required permission.
- `Deadlock` = 7001: The operation was chosen as a deadlock victim. Safe to retry.
- `SerializationFailure` = 7002: The operation conflicted with a concurrent transaction. Safe to retry.
- `Timeout` = 7003: The command or a lock wait timed out. Safe to retry.
- `Throttled` = 7004: The server is rate-limiting or out of connections. Safe to retry later.
- `ConnectionFailure` = 7005: The database couldn't be reached, or the connection dropped. Safe to retry.
- `NotSupported` = 8001: The provider doesn't support the requested operation or feature.
- `ProviderError` = 9001: A native error the provider doesn't map; see NativeCode and SqlState.

### ArxErrorCategory

enum in `ARX.SDK`, package `ARX.SDK`.

```csharp
public enum ArxErrorCategory
```

The category of an `ArxErrorCode`, given by its thousands digit.

Values:

- `Validation` = 1: ARX refused the call before sending it: invalid input, a misused connection, transaction or batch scope, or a name that looks like SQL injection.
- `NotFound` = 2: The rows the call addressed weren't found as asked: none, several where one was required, or one at another version than the call carried (ARX2004). Nothing was changed.
- `Constraint` = 3: The database refused the change because of a rule: a unique key, a foreign key, NOT NULL, CHECK, or a routine's own error.
- `Data` = 4: A value doesn't fit its column: out of range, too long, in the wrong format or of the wrong type.
- `Schema` = 5: A table or column doesn't exist, or a declaration in the schema catalog doesn't match the table.
- `Permission` = 6: The database user isn't allowed to do it.
- `Transient` = 7: A temporary failure: a deadlock, a conflict, a timeout, throttling or a lost connection. Safe to retry the whole operation (`IsTransient` is true).
- `NotSupported` = 8: The provider can't do what was asked, and refuses it rather than ignoring part of it.
- `Provider` = 9: A database error ARX doesn't map; the exception keeps its native code and SQLSTATE.

## Routing, paging cookies and capabilities

Sending each tenant or key to its own service, the paging cookie format, and what a provider declares it can do.

### ArxRouter

static class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxRouter<TService> : IArxRouter<TService>, IDisposable, IAsyncDisposable
```

The router `Create{TService}` makes. Disposing it disposes the services it made, not the ones it was given.

Properties:

- `IReadOnlyCollection<string> RouteKeys { get; }`: Every declared route key.

Methods:

- `static ArxRouter<TService> Create<TService>(Action<ArxRouterBuilder<TService>> configure, IServiceProvider? services = null)`: A router with the routes `configure` declares. Register it as a singleton, for example `services.AddSingleton<IArxRouter<ArxMsSqlDbService>>(sp => ArxRouter.Create<ArxMsSqlDbService>(r => r.Route("acme", …), sp))`.
  - `configure`: Declares the routes; at least one.
  - `services`: Optional: passed to the route factories.
- `TService For(string routeKey)`: The service for this key. An unknown key is ARX1001 InvalidArgument (the message doesn't echo the key).
  - `routeKey`: The key that picks the service: a tenant, a region, a shard.
- `bool TryFor(string routeKey, out TService service)`: The service for this key, or false when no route is declared for it.
  - `routeKey`: The key that picks the service: a tenant, a region, a shard.
  - `service`: The service when the key has a route; otherwise the default.
- `void Dispose()`: Disposes the services the router made.
- `ValueTask DisposeAsync()`: Disposes the services the router made.

### ArxRouterBuilder

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxRouterBuilder<TService>
```

Declares a router's routes, for `Create{TService}`.

Methods:

- `ArxRouterBuilder<TService> Route(string routeKey, Func<IServiceProvider, TService> factory)`: A route whose service the router makes on first use, and disposes with itself.
  - `routeKey`: The key callers pass to `For`.
  - `factory`: Makes the service; it gets the service provider given to `Create{TService}` (null without one).
- `ArxRouterBuilder<TService> Route(string routeKey, Func<TService> factory)`: A route whose service the router makes on first use, and disposes with itself.
  - `routeKey`: The key that picks this service.
  - `factory`: Makes the service for this key.
- `ArxRouterBuilder<TService> Route(string routeKey, TService service)`: A route to a service the application made and owns: the router never disposes it.
  - `routeKey`: The key that picks this service.
  - `service`: The service for this key.
- `ArxRouterBuilder<TService> KeyComparer(StringComparer comparer)`: How route keys compare: ordinal and case-sensitive by default.
  - `comparer`: How keys are compared (for example `OrdinalIgnoreCase`); ordinal by default.

### IArxRouter

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxRouter<TService>
```

Sends a call to the right service for a route key: a tenant, a region, a database. One service per key, made on first use and kept, so the router is a singleton like the services it holds. There is no mutable "current tenant": each call asks the router for its own key, so concurrent requests never see each other's.

Properties:

- `IReadOnlyCollection<string> RouteKeys { get; }`: Every declared route key.

Methods:

- `TService For(string routeKey)`: The service for this key. An unknown key is ARX1001 InvalidArgument (the message doesn't echo the key).
  - `routeKey`: The key that picks the service: a tenant, a region, a shard.
- `bool TryFor(string routeKey, out TService service)`: The service for this key, or false when no route is declared for it.
  - `routeKey`: The key that picks the service: a tenant, a region, a shard.
  - `service`: The service when the key has a route; otherwise the default.

### ArxPagingCookie

static class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public static class ArxPagingCookie
```

Writes and reads the opaque cookies of token paging (`PagingCookie`), for providers that declare `ArxCapability.TokenPaging`. A cookie carries the provider's own state (for example DynamoDB's last evaluated key) with a version, the provider's name and a fingerprint of the query it belongs to; with a signing key it is also signed (HMAC-SHA256), so a client can't forge or edit one. A cookie from another provider, another query, another key, or one that was changed is ARX1001 InvalidArgument, and the message never echoes it.

Properties:

- `const int MaxLength`: The longest cookie ARX reads, in characters: anything longer is refused before decoding.
- `static byte[] ProcessKey { get; }`: This process's own random key: the key of every service that is given none, so services made per request still read each other's cookies. It changes with every process: another instance, or a restart, needs a shared key.

Methods:

- `static string Encode(string providerName, ReadOnlySpan<byte> state, string? query = null, byte[]? signingKey = null)`: A cookie for the next page.
  - `providerName`: The provider writing it (checked when it is read back).
  - `state`: The provider's position, in its own encoding.
  - `query`: A description of the query the cookie belongs to (its source, filter and order, never the page): a cookie used with another query is refused. Null for none.
  - `signingKey`: Optional: a key of at least 32 bytes to sign the cookie with. The same key reads it back.
- `static byte[] Decode(string cookie, string providerName, string? query = null, byte[]? signingKey = null)`: The provider's state from a cookie it wrote; ARX1001 when the cookie isn't one.
  - `cookie`: The cookie from `PagingCookie`.
  - `providerName`: The provider reading it: a cookie written by another is refused.
  - `query`: The same description of the query that `Encode` was given.
  - `signingKey`: The key it was signed with; null when it wasn't signed. A signed cookie read without the key, or the reverse, is refused.
- `static string Encode(string providerName, ReadOnlySpan<byte> state, string query, byte[] key, ArxPagingCookieProtection protection)`: A cookie for the next page, protected as `protection` says: `Sealed` (version 2: encrypted and authenticated, AES-256-GCM, so a client can neither read nor change it), `Signed` (version 1, HMAC-SHA256: readable, not changeable) or `Plain` (version 1, unsigned).
  - `providerName`: The provider writing it (checked when it is read back).
  - `state`: The provider's position, in its own encoding.
  - `query`: A description of the query the cookie belongs to; a cookie used with another query is refused. Null for none.
  - `key`: The key (32 bytes or more) for Sealed and Signed; ignored for Plain.
  - `protection`: How the cookie is protected.
- `static byte[] Decode(string cookie, string providerName, string query, byte[] key, ArxPagingCookieProtection protection)`: The provider's state from a cookie protected as `protection` says; ARX1001 when it isn't one: a cookie protected otherwise, changed, written by another provider or for another query, or sealed with another key (another instance of the application, or before a restart, without a shared key).
  - `cookie`: The cookie from `PagingCookie`.
  - `providerName`: The provider reading it.
  - `query`: The same description of the query that Encode was given.
  - `key`: The key it was sealed or signed with; ignored for Plain.
  - `protection`: The protection the service requires.
- `static byte[] NewKey()`: A new random key for paging cookies: 32 bytes.

### ArxCapability

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxCapability
```

The features that differ between providers. A provider declares the ones it supports, so code can choose a path before it calls. The flags never replace the rule: a provider refuses an unsupported part of a call with `ArxNotSupportedException` (ARX8001) naming it, and never ignores it.

Values:

- `None` = 0: No feature.
- `Joins` = 1 << 0: Linked entities in a query (`ArxLinkEntity`): SQL joins, MongoDB `$lookup`.
- `Aggregates` = 1 << 1: Aggregates and grouping in a query (`AggregateInfo`).
- `OffsetPaging` = 1 << 2: Paging by page number (`PageInfo.PageNumber` beyond 1).
- `TokenPaging` = 1 << 3: Paging by an opaque cookie from the previous page (`PageInfo.PagingCookie`).
- `TotalCount` = 1 << 4: The total of matching rows (`PageInfo.ReturnTotalRecordCount`).
- `Transactions` = 1 << 5: ARX transactions and batch scopes across several calls.
- `BulkWrite` = 1 << 6: CreateMultiple, UpdateMultiple and DeleteMultiple.
- `Upsert` = 1 << 7: Reserved for an insert-or-update operation. ARX has none yet, so no provider declares it.
- `StoredProcedures` = 1 << 8: Execute: stored procedures and functions (`ArxProcedureExpression`).
- `FullTextSearch` = 1 << 9: Full-text search conditions (`ArxFullTextSearch`).
- `LikeOperators` = 1 << 10: Pattern conditions: Like, BeginsWith, EndsWith, Contains (and their negations).
- `OrFilters` = 1 << 11: Filters joined by Or (`ArxFilterExpression` with the Or operator).
- `SecondaryIndexQuery` = 1 << 12: A read that names a secondary index (DynamoDB GSIs). Relational databases choose indexes themselves and don't declare it.
- `OptimisticConcurrency` = 1 << 13: Optimistic concurrency: a table's version column (`ArxSchemaCatalogBuilder.Version`) kept and checked on writes (ARX2004).
- `SchemaResolution` = 1 << 14: Without a schema catalog, the service reads each table's id column, keys and column types from the database when a call needs them. Without this capability, a service with no catalog refuses an undeclared table (ARX1016).
- `Savepoints` = 1 << 15: A batch scope can undo one failed call alone, through a savepoint (`Savepoints`). Without it the default batch scope has no savepoints, and asking for them is ARX8001.
- `WriteByFilter` = 1 << 16: Update and delete by a filter: `UpdateMultipleAsync(values, filter)` and `DeleteMultipleAsync(table, filter)` change the rows a filter of the table's own columns matches. DynamoDB declares it with a rule: the filter must give the partition key (else ARX8001), and at most 100 items change.

### IArxProviderCapabilities

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxProviderCapabilities
```

What a provider supports, as `ArxCapability` flags.

Properties:

- `string ProviderName { get; }`: The provider's name, as messages show it (for example "PostgreSQL").
- `ArxCapability Supported { get; }`: Every supported feature.

Methods:

- `bool Supports(ArxCapability capability)`: True when every flag in `capability` is supported. `None` is always true.
  - `capability`: One capability, or several combined with `|`: all must be supported.

### ArxProviderCapabilities

class in `ARX.SDK.Providers`, package `ARX.SDK`.

```csharp
public sealed class ArxProviderCapabilities : IArxProviderCapabilities
```

The capabilities a provider declares: a fixed set of flags with its name.

Constructors:

- `new ArxProviderCapabilities(string providerName, ArxCapability supported)`: A provider's declared features.
  - `providerName`: The provider's name, as messages show it.
  - `supported`: Every feature it supports.

Properties:

- `string ProviderName { get; }`: The provider's name, as messages show it (for example "PostgreSQL").
- `ArxCapability Supported { get; }`: Every supported feature.

Methods:

- `bool Supports(ArxCapability capability)`: True when every flag in `capability` is supported. `None` is always true.
  - `capability`: One capability, or several combined with `|`: all must be supported.
- `void Require(ArxCapability capability, string feature, string? advice = null)`: Throws `ArxNotSupportedException` (ARX8001) naming `feature` and the provider when any flag in `capability` isn't supported.
  - `capability`: The features the call needs.
  - `feature`: What the call asked for, as the message names it (for example "PageInfo.PagingCookie").
  - `advice`: Optional: what to do instead.
- `void RequireSchemaFeatures(ArxSchemaCatalog schema)`: Throws `ArxNotSupportedException` (ARX8001) when `schema` declares something this provider can't keep: a version column (`OptimisticConcurrency`) without the capability. A provider calls it wherever it takes a schema (its constructor, a call's own schema), so a declaration is never silently ignored.
  - `schema`: The schema given to the provider; null declares nothing.
- `IReadOnlyList<ArxCapability> ToList()`: The supported features, by name.

## Other public types

The public types no group above lists: less common needs, extension points and interop.

### ArxAggregateColumn

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public class ArxAggregateColumn
```

One aggregate of a query: an operator over an attribute, read back under an alias.

Constructors:

- `new ArxAggregateColumn()`: An empty aggregate column; set its properties.
- `new ArxAggregateColumn(string aliasName, string attributeName, ArxAggregateOperator aggregateOperator)`: An aggregate column: `aliasName`, the attribute it reads and the operator.
  - `aliasName`: The attribute the result is read into, on each group's record.
  - `attributeName`: The column to aggregate (`alias.column` for a link's); empty for a Count of rows.
  - `aggregateOperator`: The aggregate: Count, CountDistinct, Sum, Avg, Min, Max and the others.

Properties:

- `string AliasName { get; set; }`: The name the result holds the value under.
- `string AttributeName { get; set; }`: The attribute aggregated; empty for a row count.
- `ArxAggregateOperator Operator { get; set; }`: What is computed.

### ArxAttributeCollection

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public class ArxAttributeCollection : IEnumerable<KeyValuePair<string, object?>>
```

An entity's attributes: names and their values. Names are kept as given and matched ignoring case, on read and on write: `entity["Name"]` finds `name`, and setting `entity["Name"]` replaces it. A result with two columns whose names differ only in case is refused (ARX1004).

Unlike `ArxEntity`'s indexer, which gives null for a name the entity doesn't have, this collection's indexer throws `KeyNotFoundException`: use `TryGetValue` or `ContainsKey`.

Constructors:

- `new ArxAttributeCollection()`: An empty collection; names are matched ignoring case.
- `new ArxAttributeCollection(IDictionary<string, object?> dictionary)`: A collection over this dictionary, used as it is (not copied): its comparer decides how names match, so pass one with `OrdinalIgnoreCase` to match the rest of ARX.
  - `dictionary`: The attributes to start with; names are matched ignoring case.

Properties:

- `object? this[string key] { get; set; }`: The value of an attribute; `KeyNotFoundException` when the collection doesn't have it.
- `int Count { get; }`: The number of attributes.
- `ICollection<string> Keys { get; }`: The attribute names.
- `ICollection<object?> Values { get; }`: The attribute values.

Methods:

- `void Add(string key, object? value)`: Adds an attribute; `ArgumentException` when one with that name (ignoring case) is there.
  - `key`: The attribute name.
  - `value`: Its value; null writes NULL.
- `void Add(KeyValuePair<string, object?> item)`: Adds an attribute.
  - `item`: The name and value.
- `void AddRange(IEnumerable<KeyValuePair<string, object?>>? items)`: Adds the attributes.
  - `items`: The names and values; null adds nothing.
- `void AddRange(params KeyValuePair<string, object?>[] items)`: Adds the attributes.
  - `items`: The names and values.
- `void Clear()`: Removes every attribute.
- `bool Contains(string key)`: True when an attribute has this name (ignoring case).
  - `key`: The attribute name.
- `bool Contains(KeyValuePair<string, object?> item)`: True when this name and value are present.
  - `item`: The name and value to look for.
- `bool ContainsKey(string key)`: True when an attribute has this name (ignoring case).
  - `key`: The attribute name.
- `void CopyTo(KeyValuePair<string, object?>[] array, int arrayIndex)`: Copies the attributes into an array.
  - `array`: The array to copy into.
  - `arrayIndex`: Where in the array the first attribute goes.
- `bool Remove(string key)`: Removes the attribute with this name; true when it was there.
  - `key`: The attribute name.
- `bool Remove(KeyValuePair<string, object?> item)`: Removes this name and value; true when it was there.
  - `item`: The name and value to remove.
- `bool TryGetValue(string key, out object? value)`: Gets an attribute's value; false when the collection doesn't have it.
  - `key`: The attribute name, matched ignoring case.
  - `value`: The value when found; otherwise null.
- `IEnumerator<KeyValuePair<string, object?>> GetEnumerator()`: The attributes, as name and value pairs.

### ArxBatchDataServiceExtensions

static class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public static class ArxBatchDataServiceExtensions
```

Batch-scope helpers shared by every provider.

Methods:

- `static Task RunBatchAsync(this IArxBatchDataService service, Func<IArxBatchScope, Task> body, ArxBatchOptions? options = null, CancellationToken cancellationToken = default)`: Runs `body` in a new batch scope with automatic commit: the scope is committed when the body returns, and rolled back if it throws, whether an ARX call or the developer's own code failed. The exception is rethrown unchanged. A failure the body catches itself doesn't stop the commit when savepoints undid that call alone (the rest is kept). When the failed call rolled the whole scope back instead (no savepoints: MongoDB, DynamoDB, or `Savepoints = false`), nothing was kept, so RunBatchAsync throws ARX1015 TransactionAborted when the body returns rather than return as if the work were saved. A body that commits or rolls back itself ends the scope, and nothing more is done.
  - `service`: The service that opens the scope.
  - `body`: The scope's work: every call it makes on the scope runs in one transaction, committed when it returns.
  - `options`: The scope's options; null for the defaults (no savepoints).
  - `cancellationToken`: Cancels the call.
- `static Task<T> RunBatchAsync<T>(this IArxBatchDataService service, Func<IArxBatchScope, Task<T>> body, ArxBatchOptions? options = null, CancellationToken cancellationToken = default)`: As `RunBatchAsync`, for a body that returns a value (the ids it created, a count): the value is returned once the scope is committed.
  - `service`: The service that opens the scope.
  - `body`: The scope's work: every call it makes on the scope runs in one transaction, committed when it returns.
  - `options`: The scope's options; null for the defaults (no savepoints).
  - `cancellationToken`: Cancels the call.

### ArxBatchScope

class in `ARX.SDK.Providers`, package `ARX.SDK`.

```csharp
public abstract class ArxBatchScope : IArxBatchScope
```

The behaviour every provider's batch scope shares: call numbering, failure handling, state, the one-call-at-a-time rule and rollback on dispose. A provider supplies only the database work.

When a call fails with an `ArxException`, its `BatchNumber` is set. With savepoints, `UndoFailedCallAsync` undoes that call alone; if it can't (for example the connection dropped), the whole scope is rolled back. Without savepoints, and for any other exception (cancellation included), the whole scope is rolled back. The original exception is always the one thrown.

Properties:

- `ArxBatchState State { get; }`: The scope's state.
- `int BatchCount { get; }`: The number of calls made through the scope, successful or not. Reads count too. Each call's number (1-based) is its batch number.
- `long RowsWritten { get; }`: Rows written by successful calls that are still in the transaction; 0 once the scope is rolled back.
- `IReadOnlyList<int> FailedBatches { get; }`: The batch numbers of the calls that failed, in order.

Methods:

- `Task<ArxRecordId> CreateAsync(ArxEntity entity, CancellationToken cancellationToken = default)`: Inserts one entity inside the scope's transaction and returns its id, which is also set on `RecordId`.
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, CancellationToken cancellationToken = default)`: Inserts the entities inside the scope's transaction, all or nothing, and returns their ids: one per entity, in list order, the same instances that are set on each entity's `RecordId`. An empty list returns an empty list.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the rows `entity` matches inside the scope's transaction and returns how many changed. Nothing matched is ARX2002.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the entities inside the scope's transaction, all or nothing, and returns the rows changed. An entity that matched nothing refuses the whole call (ARX2002). An empty list returns 0.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The update by a filter inside the scope's transaction: returns how many rows changed.
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The delete by a filter inside the scope's transaction: returns how many rows went.
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, CancellationToken cancellationToken = default)`: CreateMultiple with options inside the scope's transaction.
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, CancellationToken cancellationToken = default)`: Deletes the record with this id inside the scope's transaction; false when there was none. The id converts from a `long`, `int`, `Guid` or `string`, so `DeleteAsync("account", 42L)` works as it is.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows `entity` matches inside the scope's transaction and returns how many went.
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync<TId>(string entityName, IReadOnlyCollection<TId> ids, CancellationToken cancellationToken = default)`: Deletes the records with these ids inside the scope's transaction, all or nothing, and returns how many existed. Duplicates count once. One method for every id type: a list of `long`, `int`, `Guid`, `string` or `ArxRecordId`; another element type is ARX1007 UnsupportedValueType.
  - `entityName`: The table to delete from.
  - `ids`: The ids of the records to delete; ids that match nothing are left out of the count.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the rows the entities match inside the scope's transaction, all or nothing, and returns how many went.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Reads one record by id (the value Create returned, or a `long`, `int`, `Guid` or `string`) inside the scope's transaction; null when not found. On the SQL providers and MongoDB it sees the scope's own writes; DynamoDB sends writes at commit, so a read before it sees only what is committed.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Reads the one record the entity matches (an ArxMatch in `Match`) inside the scope's transaction.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Runs a query inside the scope's transaction. On the SQL providers and MongoDB it sees the scope's own writes; on DynamoDB, only what is committed.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a procedure or function inside the scope's transaction: it sees the scope's writes, and a failed call is undone alone. A procedure that commits or rolls back by itself can't run in a scope (ARX8001).
  - `procedure`: The procedure or function to call, with its arguments.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task CommitAsync(CancellationToken cancellationToken = default)`: Commits everything written through the scope. If the database refuses the commit (for example a deferred constraint), the error is thrown and the scope is `RolledBack`. If the connection fails or times out before the database answers, the scope is `OutcomeUnknown` and the error, not transient, says the work may or may not be saved. A token cancelled before the commit starts rolls the scope back; the commit itself isn't cancelled, because stopping it half way would leave its outcome unknown.
  - `cancellationToken`: Cancels the call.
- `Task RollbackAsync(CancellationToken cancellationToken = default)`: Rolls back everything written through the scope. Does nothing if the scope is already rolled back; fails with ARX1010 if it was committed. The rollback itself isn't cancelled.
  - `cancellationToken`: Cancels the call.
- `ValueTask DisposeAsync()`: Rolls back a scope that wasn't committed, then releases its connection. Never throws for a failed rollback.

### ArxBatchState

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxBatchState
```

The state of a batch scope.

Values:

- `Active`: The transaction is open and calls can be made.
- `Committed`: The transaction was committed. Any further call fails with ARX1010.
- `RolledBack`: The transaction was rolled back (explicitly, by a failure, or on dispose). Any further call fails with ARX1010.
- `OutcomeUnknown`: The commit got no answer (the connection failed or timed out while committing): the work may have been saved or not. Check what is in the database before doing it again. Any further call fails with ARX1010.

### ArxConnection

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public abstract class ArxConnection : IAsyncDisposable
```

A connection to one database, opened and closed by ARX. Each provider has its own; this provider's is `new ArxMsSqlConnection(connectionString)`. Begin a transaction on it and pass the transaction to service calls; application code never needs the database driver's types.

One transaction at a time per connection, and one call at a time. Disposing it closes the connection.

Methods:

- `Task<ArxTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default)`: Opens the connection if needed and begins a transaction.
  - `cancellationToken`: Cancels the call.
- `ValueTask DisposeAsync()`: Closes the connection. An active transaction on it is rolled back.

### ArxCreateMultipleOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxCreateMultipleOptions
```

Options for `CreateMultipleAsync(entities, options)`.

Properties:

- `bool ReturnIds { get; init; }`: True, the default: the new ids are read back and returned, as `CreateMultipleAsync(entities)` does. False: no id is read back, so the provider can take its bulk path (PostgreSQL's binary `COPY`, SQL Server's `SqlBulkCopy`), and the call returns `None` for every entity. Still all or nothing.

### ArxDiagnostics

static class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public static class ArxDiagnostics
```

ARX's tracing and metrics, on .NET's own instruments, so OpenTelemetry (`AddSource("ARX.SDK")`, `AddMeter("ARX.SDK")`) or any `ActivityListener` and `MeterListener` read them:

- an activity per operation (`Create`, `RetrieveMultiple`, …), kind Client, named "operation table", tagged `db.system.name`, `db.operation.name`, `db.collection.name` and `arx.provider`; on failure the status Error, `error.type` and `arx.error.code`;
- `arx.operation.duration` (a histogram, in seconds) and `arx.operation.errors` (a counter), with the same tags.
Values are never recorded, only names. Without a listener, each operation costs a check.

Properties:

- `const string SourceName`: The name of ARX's `ActivitySource` and `Meter`: `ARX.SDK`.
- `static readonly ActivitySource Source`: The source of ARX's activities.
- `static readonly Meter Meter`: The meter of ARX's metrics.

Methods:

- `static Task<T> TraceAsync<T>(string provider, string dbSystem, string operation, string table, Func<Task<T>> work)`: Traces one operation of a provider. For the providers' use: applications read the activities and metrics instead.
  - `provider`: The provider's name ("PostgreSQL").
  - `dbSystem`: The database, as OpenTelemetry names it ("postgresql", "microsoft.sql_server", "mysql", "mongodb", "aws.dynamodb").
  - `operation`: The operation ("Create", "RetrieveMultiple", …).
  - `table`: The table or entity, when known.
  - `work`: The operation itself.
- `static Task TraceAsync(string provider, string dbSystem, string operation, string table, Func<Task> work)`: As `TraceAsync{T}`, for an operation without a result.
  - `provider`: The provider's name ("PostgreSQL").
  - `dbSystem`: The database, as OpenTelemetry names it ("postgresql", "microsoft.sql_server", "mysql", "mongodb", "aws.dynamodb").
  - `operation`: The operation ("Create", "RetrieveMultiple", …).
  - `table`: The table or entity, when known.
  - `work`: The operation itself.

### ArxFilterWrite

static class in `ARX.SDK.Providers`, package `ARX.SDK`.

```csharp
public static class ArxFilterWrite
```

For the providers' writes by a filter: the rules every provider applies the same way, before anything is sent.

Methods:

- `static void CheckFilter(string entityName, ArxFilterExpression filter, ArxFilterWriteOptions? options, string operation, string? provider)`: Checks the filter: ARX1001 when it has no condition and `AllRows` isn't set, or when it names a link (a condition with an entity name other than the table, or an `alias.column` name).
  - `entityName`: The table written.
  - `filter`: The filter that chooses the rows.
  - `options`: The call's options, or null.
  - `operation`: "UpdateMultiple" or "DeleteMultiple", for the message.
  - `provider`: The provider's name, for the error.
- `static void CheckValues(ArxEntity values, ArxTableDefinition? table, string? provider)`: Checks the values an update by a filter writes: at least one; not the id (the attribute, or a `RecordId` with a value), since a filter and an id can't both say which rows; not the version column, which ARX moves on every changed row.
  - `values`: The entity whose attributes are the values to set.
  - `table`: The table's declaration, when the call has one (a catalog, or what was resolved).
  - `provider`: The provider's name, for the error.
- `static bool IsEmpty(ArxFilterExpression filter)`: True when the filter has no condition at any depth.
  - `filter`: The filter.

### ArxFilterWriteOptions

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxFilterWriteOptions
```

Options for an update or delete by a filter (`UpdateMultipleAsync(values, filter)`, `DeleteMultipleAsync(table, filter)`).

Properties:

- `bool AllRows { get; init; }`: True to let an empty filter (no conditions) change or delete every row of the table. False, the default: an empty filter is ARX1001, so a filter that was never filled in can't touch every row by mistake.

### ArxFullTextSearch

class in `ARX.SDK.Models`, package `ARX.SDK`.

```csharp
public class ArxFullTextSearch
```

A full-text search, given as a condition's value: `query.Criteria.AddCondition("body", ArxConditionOperator.Equal, new ArxFullTextSearch("quick fox"))`. Each database runs its own full-text search: PostgreSQL `to_tsvector('english', column) @@ websearch_to_tsquery('english', text)` (English stemming and stop words); SQL Server `FREETEXT` and MySQL `MATCH … AGAINST` in natural language mode, which need a full-text index on the column (ARX8001 without one); MongoDB `$text`, which searches the collection's text index whatever field the condition names. DynamoDB has none (ARX8001); `ArxCapability.FullTextSearch` says which providers do.

The operator is `Equal` or `Contains` (and `Like` on the SQL providers): all mean "matches the search". The text is a parameter, never part of the statement. The matching rules (stemming, stop words, ranking, the minimum word length) are the database's, so the same search can find different rows on each provider.

Constructors:

- `new ArxFullTextSearch(string searchText)`: A full-text search for `searchText`.
  - `searchText`: The words to search for, as the database's full-text search reads them.

Properties:

- `string SearchText { get; set; }`: The words to search for. Empty or whitespace is ARX1001.

### ArxFunctionArgument

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxFunctionArgument
```

One argument of a function row source: by name (`p_region => $1`) or by position (`Name` null).

Constructors:

- `new ArxFunctionArgument(string? name, object? value)`: An argument whose value says its type.
  - `name`: The function's parameter name; null to pass it by position.
  - `value`: The value, sent as a parameter.
- `new ArxFunctionArgument(string? name, object? value, Type? type, bool variadic)`: An argument with its type declared, or passed to a `VARIADIC` parameter.
  - `name`: The function's parameter name; null to pass it by position.
  - `value`: The value, sent as a parameter.
  - `type`: The argument's .NET type, sent as a cast, for a null the database can't type by itself.
  - `variadic`: The value is an array passed to a `VARIADIC` parameter.

Properties:

- `Type? DeclaredType { get; }`: The declared .NET type, sent as a cast; null to let the value (or the database) decide.
- `bool IsVariadic { get; }`: The value is an array passed to a `VARIADIC` parameter (`VARIADIC $1`).
- `string? Name { get; }`: The parameter's name, or null for a positional argument.
- `object? Value { get; }`: Sent as a typed parameter, like a write's value. Null is SQL NULL.

### ArxInjectionCheck

static class in `ARX.SDK.Providers`, package `ARX.SDK`.

```csharp
public static class ArxInjectionCheck
```

The rule every provider uses to tell a name that looks like an SQL injection attempt (ARX1017 SuspectedInjection) from a plain invalid name (ARX1003 InvalidIdentifier).

A provider calls `Inspect` only for a name that has already **failed** its identifier rules, so this check never refuses a name the provider accepts: it only decides which code the refusal carries.

Values are never inspected. They are always sent as parameters, so text such as `Robert'); DROP TABLE x;--` is stored exactly as typed and can't change the SQL; refusing it would refuse real data (O'Brien, "a -- b").

Properties:

- `const int MAX_ECHO_LENGTH`: The longest part of a suspicious name an error message repeats.

Methods:

- `static string? Inspect(string? name)`: What makes `name` look like an injection attempt (for example `contains ';'` or `contains the SQL word 'UNION'`), or null when it doesn't (a space alone, a leading digit or a long name is a plain invalid name).
  - `name`: The name that failed the identifier rules, as the caller gave it.
- `static string Echo(string? name)`: `name` made safe to put in a message or a log line: control characters and line breaks escaped (so the name can't forge log lines), and cut to `MAX_ECHO_LENGTH` characters.
  - `name`: The name to quote in a message.
- `static ArxValidationException Refuse(string kind, string? name, string evidence, string? provider = null)`: The ARX1017 error for a `kind` name ("Entity", "Attribute", "Type", …) that `Inspect` found suspicious, with `evidence` as returned by it. Providers raise this, so the message is the same everywhere.
  - `kind`: What the name is, for the message: "Entity", "Attribute", "Type" and so on.
  - `name`: The suspicious name, quoted safely in the message.
  - `evidence`: What `Inspect` found in it.
  - `provider`: The provider's name for `Provider`, or null.

### ArxMatchKind

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxMatchKind
```

How an update or delete finds its rows.

Values:

- `Id`: By the table's declared id column.
- `Key`: By one of the table's declared business keys.
- `Columns`: By any columns the developer names, declared or not.

### ArxPagingCookieProtection

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxPagingCookieProtection
```

How a provider protects its paging cookies. A cookie carries the last item's key values, which can be an email or a tenant id, so the default seals it.

Values:

- `Sealed` = 0: Encrypted and authenticated (AES-256-GCM): a client can neither read a cookie nor change it. The default.
- `Signed` = 1: Signed (HMAC-SHA256): a client can read a cookie's key values, but not change them.
- `Plain` = 2: Neither: a client can read and change a cookie. ARX still checks the provider and the query it belongs to, and the query's filter applies to every page, so an edited cookie can't reach other records; it can only move within them.

### ArxPagingParametersStyle

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxPagingParametersStyle
```

How a routine that pages itself names its page arguments and its total (way 1).

Values:

- `PageNumber`: A page number (from 1) and a page size.
- `OffsetLimit`: An offset (rows to skip) and a limit (rows to return). ARX asks for one row more, so HasNextPage is exact.

### ArxPreLoadTypes

static class in `ARX.SDK.Providers`, package `ARX.SDK`.

```csharp
public static class ArxPreLoadTypes
```

The type names a catalog's JSON uses.

Methods:

- `static string NameOf(Type type)`: A type's JSON name: `long`, `string`, `DateOnly`, `string[]`.
  - `type`: A .NET type a column can hold.
- `static Type TypeOf(string name)`: The type of a JSON name; ARX1001 for one it doesn't know.
  - `name`: A type's JSON name, as `NameOf` writes it.

### ArxResultColumn

class in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public sealed class ArxResultColumn
```

A result column of a function that returns untyped rows (`SETOF record`): its name and .NET type.

Constructors:

- `new ArxResultColumn(string name, Type type)`: A column a row source returns: its name and .NET type.
  - `name`: The column's name in the function's result.
  - `type`: The .NET type it is read as.

Properties:

- `string Name { get; }`: The column's name.
- `Type Type { get; }`: The column's .NET type.

### ArxRowSourceKind

enum in `ARX.SDK.Query`, package `ARX.SDK`.

```csharp
public enum ArxRowSourceKind
```

What a row source is.

Values:

- `Table`: A table or view (on PostgreSQL also a materialized view or foreign table): anything read by name.
- `Function`: A function that returns rows (a table, a set, one row or one value), called with arguments.

### ArxSelectionSetCatalog

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSelectionSetCatalog : IArxSelectionSetCatalog
```

A ready-made, immutable, thread-safe catalog. Build one with `Create`.

Properties:

- `IReadOnlyCollection<ArxSelectionSetDefinition> Sets { get; }`: Every set, in the order added.

Methods:

- `static ArxSelectionSetCatalogBuilder Create()`: Starts a selection set catalog: add each set, then call Build.
- `bool TryGetSet(string name, out ArxSelectionSetDefinition set)`: Gets a selection set by name; false when the catalog has none of that name.
  - `name`: The selection set's name.
  - `set`: The set when found; otherwise null.

### ArxSelectionSetCatalogBuilder

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxSelectionSetCatalogBuilder
```

Builds an `ArxSelectionSetCatalog`. Not thread-safe; build once, at startup.

Methods:

- `ArxSelectionSetCatalogBuilder Add(ArxSelectionSetDefinition set)`: Adds a set the developer defined (for example loaded from their own option tables).
  - `set`: A selection set built elsewhere.
- `ArxSelectionSetCatalogBuilder Add(string name, ArxSelectionSetKind kind, params (object Value, string DisplayText)[] options)`: Adds a single-choice set; options get their order from their position.
  - `name`: The set's name, used when writing and reading its values.
  - `kind`: What its codes are: integers, text or single characters.
  - `options`: The options: each code and its display text.
- `ArxSelectionSetCatalogBuilder Add(string name, ArxSelectionSetKind kind, ArxSelectionSetMultiplicity multiplicity, params (object Value, string DisplayText)[] options)`: Adds a set with the given storage form; options get their order from their position.
  - `name`: The set's name, used when writing and reading its values.
  - `kind`: What its codes are: integers, text or single characters.
  - `multiplicity`: One option per column, or several stored as an array.
  - `options`: The options: each code and its display text.
- `ArxSelectionSetCatalogBuilder AddEnum<TEnum>(string? name = null)`: Adds a single-choice Integer set from a .NET enum: codes are the enum's values (in its underlying type), display text its names.
  - `name`: The set's name; the enum's name when null.
- `ArxSelectionSetCatalogBuilder AddFlagsEnum<TEnum>(string? name = null)`: Adds a Flags set from a `[Flags]` enum. The zero member ("None") isn't an option; every other member must be a single bit.
  - `name`: The set's name; the enum's name when null.
- `ArxSelectionSetCatalog Build()`: The catalog, read-only from now on.

### ArxSelectionSetExtensions

static class in `ARX.SDK.Extensions`, package `ARX.SDK`.

```csharp
public static class ArxSelectionSetExtensions
```

Reading selection sets. Retrieve returns the raw stored value; these turn it into the code, or into an `ArxSelectionSetValue` with display text from the developer's catalog.

Methods:

- `static T? GetSelectionSetValue<T>(this ArxEntity entity, string attribute)`: The raw code as `T`, whether the attribute holds a plain value or an `ArxSelectionSetValue`. Integer codes convert between integer types and to enums; string codes convert to enums by name. Missing or null gives `default`.
  - `entity`: The record that was read.
  - `attribute`: The column that holds the selection set's value.
- `static ArxSelectionSetValue? GetSelectionSet(this ArxEntity entity, string attribute, string setName, IArxSelectionSetCatalog catalog)`: The attribute decoded through set `setName` of `catalog`: multiple-choice storage (array, flags, delimited, JSON) turned back into `Values`, with the matched `Options` and `DisplayText`. A stored code missing from the set doesn't throw: its option is null and `IsDefined` is false. Missing or null gives null.
  - `entity`: The record that was read.
  - `attribute`: The column that holds the selection set's value.
  - `setName`: The selection set's name, as the catalog declares it.
  - `catalog`: The catalog that declares the selection set.
- `static string? GetSelectionSetDisplayText(this ArxEntity entity, string attribute, string setName, IArxSelectionSetCatalog catalog)`: The display text of the attribute's option (or options, joined with ", "), from the catalog; null when missing, null or not in the set.
  - `entity`: The record that was read.
  - `attribute`: The column that holds the selection set's value.
  - `setName`: The selection set's name, as the catalog declares it.
  - `catalog`: The catalog that declares the selection set.

### ArxSelectionSets

static class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public static class ArxSelectionSets
```

The write-side checks every provider runs for an `ArxSelectionSetValue`, before any database access.

Methods:

- `static ArxSelectionSetWrite PrepareWrite(IArxSelectionSetCatalog? catalog, ArxSelectionSetValue value, string? entityName, string? attributeName, string? provider = null)`: Checks the value against `catalog` and returns what to write.
  - `catalog`: The catalog that declares the selection set.
  - `value`: The value to write.
  - `entityName`: The table, for the error message.
  - `attributeName`: The column, for the error message.
  - `provider`: The provider's name, for the error.

### ArxSelectionSetWrite

record in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed record ArxSelectionSetWrite
```

What a provider writes for one `ArxSelectionSetValue`.

### ArxServerCheck

class in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed class ArxServerCheck
```

What the connected server allows, from `CheckServerAsync()`: the server's version, the provider's capabilities on this server, and for each one the server removes, why. `service.Capabilities` says what the provider can do anywhere; this says what it can do here. Call it once at startup, beside `ValidateSchemaAsync`.

Constructors:

- `new ArxServerCheck(IArxProviderCapabilities provider, string serverVersion, IEnumerable<ArxServerLimit>? limits = null, IEnumerable<string>? problems = null)`: A check: the provider's capabilities, less those the server removes.
  - `provider`: The provider's capabilities.
  - `serverVersion`: The server's version, as it reports it.
  - `limits`: The capabilities the server removes, with the reason.
  - `problems`: Anything else the check found wrong (a table of the model that doesn't exist); empty when none.

Properties:

- `string ProviderName { get; }`: The provider's name, as messages show it.
- `string ServerVersion { get; }`: The server's version, as it reports it ("16.4", "8.4.3", "7.0.12", …).
- `ArxCapability Supported { get; }`: The provider's capabilities on this server.
- `IReadOnlyList<ArxServerLimit> Limits { get; }`: The capabilities the provider has that this server doesn't allow, each with the reason.
- `IReadOnlyList<string> Problems { get; }`: Anything else the check found wrong; empty when the server is ready.
- `bool IsReady { get; }`: True when the check found nothing wrong (limits are allowed: they only remove capabilities).

Methods:

- `bool Supports(ArxCapability capability)`: True when every flag in `capability` works on this server.
  - `capability`: One capability, or several combined with `|`: all must be supported.

### ArxServerLimit

record in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public sealed record ArxServerLimit
```

A capability the provider has but the connected server doesn't allow, and why.

### ArxTransactionState

enum in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public enum ArxTransactionState
```

The state of an `ArxTransaction`.

Values:

- `Active`: Open: calls can run in it.
- `Committed`: Committed. Further calls fail with ARX1010.
- `RolledBack`: Rolled back (explicitly, on dispose, or because the commit was refused). Further calls fail with ARX1010.
- `OutcomeUnknown`: The commit got no answer (the connection failed or timed out while committing): the work may have been saved or not. Check what is in the database before doing it again; running it again blindly could save it twice. Further calls fail with ARX1010.

### IArxDataService

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxDataService : IArxBatchDataService
```

What every ARX service does, whatever its database: the operations, the capabilities, the startup checks, and batch scopes for work that must succeed or fail together. Application code can depend on it, register the provider behind it, and mock it in tests: services.AddSingleton<IArxDataService>(new ArxMsSqlDbService(connectionString, schema)); The provider types add what is theirs (connections, transactions, options); a call the provider can't do is refused with ARX8001 NotSupported, as `Capabilities` says (`ExecuteAsync` on MongoDB and DynamoDB).

Properties:

- `IArxProviderCapabilities Capabilities { get; }`: What the provider supports: a call outside it is ARX8001.

Methods:

- `Task<ArxServerCheck> CheckServerAsync(CancellationToken cancellationToken = default)`: What the connected server allows: its version, the capabilities it removes and why.
  - `cancellationToken`: Cancels the call.
- `Task ValidateSchemaAsync(CancellationToken cancellationToken = default)`: Compares every table of the schema catalog with the database, and throws with the differences.
  - `cancellationToken`: Cancels the call.
- `Task<ArxTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default)`: Begins a transaction on a connection of its own, the same way on every provider: pass the transaction to the calls, then commit it. Disposing it without committing rolls it back, and closes its connection (`await using var transaction = await service.BeginTransactionAsync();`).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: Sets `values`' attributes on every row of its table that `filter` matches, in one call, and returns how many rows changed. `UPDATE … SET … WHERE …` on the SQL databases.
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(ArxEntity values, ArxFilterExpression filter, ArxTransaction transaction, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The update by a filter inside an ARX transaction (see `UpdateMultipleAsync`).
  - `values`: The table (EntityName) and the attributes to set: null clears a column.
  - `filter`: The rows to change: conditions on the table's own columns.
  - `transaction`: The ARX transaction to run in. ARX doesn't commit or roll it back.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes every row of the table that `filter` matches, in one call, and returns how many went. The filter's rules are UpdateMultiple's: the table's own columns, and an empty filter is ARX1001 unless `AllRows` is set.
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(string entityName, ArxFilterExpression filter, ArxTransaction transaction, ArxFilterWriteOptions? options = null, CancellationToken cancellationToken = default)`: The delete by a filter inside an ARX transaction (see `DeleteMultipleAsync`).
  - `entityName`: The table to delete from.
  - `filter`: The rows to delete: conditions on the table's own columns.
  - `transaction`: The ARX transaction to run in. ARX doesn't commit or roll it back.
  - `options`: AllRows for an empty filter; null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, CancellationToken cancellationToken = default)`: Creates the records, all or nothing, as `CreateMultipleAsync`, with options. With `ReturnIds` false no id is read back: the provider can take its bulk path, a table without a usable id is created without a catalog, and every id returned is `None`.
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxCreateMultipleOptions options, ArxTransaction transaction, CancellationToken cancellationToken = default)`: CreateMultiple with options inside an ARX transaction (see `CreateMultipleAsync`).
  - `entities`: The records to create, all or nothing.
  - `options`: ReturnIds false to skip reading the ids back.
  - `transaction`: The ARX transaction to run in. ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<ArxRecordId> CreateAsync(ArxEntity entity, CancellationToken cancellationToken = default)`: Creates one record and returns its id (also set on `RecordId`).
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, CancellationToken cancellationToken = default)`: Creates the records, all or nothing, and returns their ids in the order of the list.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the records the entity finds (by its id, or the match of the options) and returns how many: 1 by id or a key; by columns every row that matches unless RequireSingleRow. None is ARX2002.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates every entity's record, all or nothing, and returns how many; one that finds none is ARX2002.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, CancellationToken cancellationToken = default)`: Deletes the record with this id: true when it was there.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the records the entity finds and returns how many (0 when none; ARX2002 with RequireSingleRow).
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the records the entities find, all or nothing, and returns how many existed.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Reads one record by id, the columns given (all when null); null when it isn't there.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Runs a query: its records, page and, when asked, total.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a procedure or function (ARX8001 where StoredProcedures isn't supported).
  - `procedure`: The procedure or function to call, with its arguments.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Reads the one record the entity finds: by its id, or by the match of the options (a declared key, columns); the columns of the options (all when null); null when none is there. On DynamoDB this is how an item of a single table (or one with a sort key) is read by its whole key.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync<TId>(string entityName, IReadOnlyCollection<TId> ids, CancellationToken cancellationToken = default)`: Deletes the records with these ids, all or nothing, and returns how many existed. Duplicates count once. One method for every id type: a list of `long`, `int`, `Guid`, `string` or `ArxRecordId`; another element type is ARX1007 UnsupportedValueType.
  - `entityName`: The table to delete from.
  - `ids`: The ids of the records to delete; ids that match nothing are left out of the count.
  - `cancellationToken`: Cancels the call.
- `Task<ArxRecordId> CreateAsync(ArxEntity entity, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Creates one record in an ARX transaction (from the provider's connection) and returns its id.
  - `entity`: The record to create: its table and the attributes to write. Its `RecordId` is set to the new id.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<IReadOnlyList<ArxRecordId>> CreateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Creates the records in an ARX transaction and returns their ids in the order of the list.
  - `entities`: The records to create, all or nothing; their ids come back in the same order.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateAsync(ArxEntity entity, ArxTransaction transaction, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates the records the entity finds, in an ARX transaction, and returns how many (as the overload without a transaction); none is ARX2002.
  - `entity`: The change: its table, the attributes to write (null clears a column; an attribute left out keeps its value), and the id, key or columns that find the row.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> UpdateMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, ArxUpdateOptions? options = null, CancellationToken cancellationToken = default)`: Updates every entity's record in an ARX transaction and returns how many; one that finds none is ARX2002.
  - `entities`: The changes, all or nothing: each carries the attributes to write and what finds its row.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<bool> DeleteAsync(string entityName, ArxRecordId id, ArxTransaction transaction, CancellationToken cancellationToken = default)`: Deletes the record with this id in an ARX transaction: true when it was there.
  - `entityName`: The table to delete from.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteAsync(ArxEntity entity, ArxTransaction transaction, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the records the entity finds in an ARX transaction and returns how many.
  - `entity`: The record to delete: its table and the id, key or columns that find it.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<int> DeleteMultipleAsync(IReadOnlyList<ArxEntity> entities, ArxTransaction transaction, ArxDeleteOptions? options = null, CancellationToken cancellationToken = default)`: Deletes the records the entities find in an ARX transaction and returns how many existed.
  - `entities`: The records to delete, all or nothing, each found by its id or by the match's columns.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the rows are found (`Match`) and checked; null for the defaults (by id).
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(string entityName, ArxRecordId id, ArxTransaction transaction, ArxColumnSet? columns = null, CancellationToken cancellationToken = default)`: Reads the record with this id in an ARX transaction, or null. On SQL and MongoDB the read sees the transaction's own writes; DynamoDB sends a transaction's writes at commit, so a read there doesn't see them yet.
  - `entityName`: The table or view to read.
  - `id`: The record's id: the value Create returned, or a plain value of the declared id's type.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `columns`: The columns to read; null or an empty set reads every column. The declared id is always read.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntity?> RetrieveAsync(ArxEntity match, ArxTransaction transaction, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Reads the one record the entity finds (by id, a key or columns) in an ARX transaction, or null.
  - `match`: The record to find: its table, and the values of the id, the declared key or the columns that find it.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxEntityCollection> RetrieveMultipleAsync(ArxQueryExpression query, ArxTransaction transaction, ArxRetrieveOptions? options = null, CancellationToken cancellationToken = default)`: Runs the query in an ARX transaction and returns the records it finds.
  - `query`: The query: its row source, columns, criteria, links, order, paging and aggregates.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: How the row is found and read (match, command timeout, lookup names); null for the defaults.
  - `cancellationToken`: Cancels the call.
- `Task<ArxExecuteResult> ExecuteAsync(ArxProcedureExpression procedure, ArxTransaction transaction, ArxExecuteOptions? options = null, CancellationToken cancellationToken = default)`: Calls a procedure or function in an ARX transaction (ARX8001 where StoredProcedures isn't declared).
  - `procedure`: The procedure or function to call, with its arguments.
  - `transaction`: The ARX transaction to run in (from the provider's connection type). ARX doesn't commit or roll it back.
  - `options`: Options of the call (paging, command timeout); null for the defaults.
  - `cancellationToken`: Cancels the call.

### IArxSelectionSetCatalog

interface in `ARX.SDK.Services`, package `ARX.SDK`.

```csharp
public interface IArxSelectionSetCatalog
```

The selection sets an application uses, defined by the developer. ARX only reads it, in memory.

Methods:

- `bool TryGetSet(string name, out ArxSelectionSetDefinition set)`: Finds a set by its exact name.
  - `name`: The selection set's name.
  - `set`: The set when found; otherwise null.

