Skip to content

High level API async CRUD

Daniel Frantík edited this page Aug 16, 2026 · 4 revisions

The O/R mapper has a Task-based half. Every method here is the counterpart of a synchronous one described in reading data and CRUD, and behaves identically apart from being awaited.

  • connection.LoadAllAsync<TEntity>
  • connection.LoadListAsync<TEntity>
  • connection.LoadSingleAsync<TEntity> / LoadSingleOrDefaultAsync<TEntity>
  • connection.LoadByIdAsync<TEntity> / LoadByNameAsync<TEntity>
  • connection.SaveAsync<TEntity>
  • connection.DeleteAsync<TEntity>
  • command.LoadListAsync<TEntity> / LoadSingleAsync<TEntity> / LoadSingleOrDefaultAsync<TEntity>
using tik4net;
using tik4net.Objects;
using tik4net.Objects.Ip;

var addresses = await connection.LoadAllAsync<IpAddress>(cancellationToken);

var address = await connection.LoadByIdAsync<IpAddress>("*1", cancellationToken);
address.Comment = "WAN";
await connection.SaveAsync(address, cancellationToken: cancellationToken);

await connection.DeleteAsync(address, cancellationToken);

SaveAsync takes the same optional usedFieldsFilter and saveMode as Save, so the cancellation token is normally passed by name.

They are the same rules, not similar ones

Everything that is not "wait for the router" is shared code, not a parallel implementation: how many rows a load may return and which exception says otherwise, the change-tracking snapshot that lets a later save send only what changed, what counts as a create, which fields are unset rather than set, and that the unsets are sent before the set. So:

  • SaveAsync on an entity loaded with a Load*Async method and then left alone sends nothing — the same skip Save performs.
  • SaveAsync writes the new .id back into the entity after a create, exactly as Save does.
  • LoadByIdAsync throws TikNoSuchItemException where LoadById does.

Filters

LoadListAsync / LoadSingleAsync / LoadSingleOrDefaultAsync take the cancellation token before the filter parameters, because a params array has to come last:

var wanAddresses = await connection.LoadListAsync<IpAddress>(
    cancellationToken,
    connection.CreateParameter("interface", "ether1"));

// no token, filter by name
var byInterface = await connection.LoadListAsync<IpAddress>(
    filterParameters: connection.CreateParameter("interface", "ether1"));

Which transports

All of them — every shipped transport declares AsyncCommands. A transport that does not (a custom ITikConnection, say) throws TikConnectionCapabilityNotSupportedException rather than block a thread and call the result asynchronous. What a CancellationToken can actually stop once the command is on the wire differs by transport — see what the CancellationToken actually does.

Not here

  • LoadWithDuration needs the Streaming capability (binary API only) and has no async form.
  • LoadAsync / LoadListenAsync are not part of this family despite the name — they are the callback monitors described in reading data, gated on Listen. The names are unfortunately close.
  • SaveListDifferences, DeleteAll, Move, MoveToEnd stay synchronous. Each is a sequence of the primitives above, and an async form of them raises a question about what should happen when the third of five writes fails — a design decision, not a mechanical translation.

See also

Clone this wiki locally