docs/docs/00200-core-concepts/00600-clients/00600-csharp-reference.md
The SpacetimeDB client for C# contains all the tools you need to build native clients for SpacetimeDB modules using C#.
If you are writing a SpacetimeDB module (tables and reducers), use these patterns:
public static partial class Module[SpacetimeDB.Table(Accessor = "table_name", Public = true)] on partial struct (or partial class) — Accessor controls generated API names, and canonical SQL names are derived unless Name is explicitly set[SpacetimeDB.PrimaryKey] on one column when you need key-based lookups or updates[SpacetimeDB.Reducer] on static methods with ReducerContext ctx as first parameterusing SpacetimeDB; and partial on all table structs and the Module classSpacetimeDB.Index.BTree (never bare Index). Bare Index is ambiguous with System.Index. For multi-column: Columns = new[] { nameof(Col1), nameof(Col2) }, not collection expressions [nameof(X)]TaggedEnum<(VariantA A, VariantB B)> with partial record, not partial classScheduledAt should reference a field of type ScheduleAt in the schedule tableSee Tables, Reducers, and Column Types for full server-side documentation. The rest of this page covers the client SDK (connections, subscriptions, callbacks).
Before diving into the reference, you may want to review:
| Name | Description |
|---|---|
| Project setup | Configure a C# project to use the SpacetimeDB C# client SDK. |
| Generate module bindings | Use the SpacetimeDB CLI to generate module-specific types and interfaces. |
DbConnection type | A connection to a remote database. |
IDbContext interface | Methods for interacting with the remote database. |
EventContext type | Implements IDbContext for row callbacks. |
ReducerEventContext type | Implements IDbContext for reducer callbacks. |
SubscriptionEventContext type | Implements IDbContext for subscription callbacks. |
ErrorContext type | Implements IDbContext for error-related callbacks. |
| Query Builder API | Type-safe query builder for typed subscription queries. |
| Access the client cache | Access to your local view of the database. |
| Observe and invoke reducers | Send requests to the database to run reducers, and register callbacks to run when notified of reducers. |
| Identify a client | Types for identifying users and client connections. |
dotnet CLI toolIf you would like to create a console application using .NET, you can create a new project using dotnet new console and add the SpacetimeDB SDK to your dependencies:
dotnet add package SpacetimeDB.ClientSDK
(See also the CSharp Quickstart for an in-depth example of such a console application.)
Add the SpacetimeDB Unity Package using the Package Manager. Open the Package Manager window by clicking on Window -> Package Manager. Click on the + button in the top left corner of the window and select "Add package from git URL". Enter the following URL and click Add.
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git
(See also the Unity Tutorial)
Each SpacetimeDB client depends on some bindings specific to your module. Create a module_bindings directory in your project's directory and generate the C# interface files using the Spacetime CLI. From your project directory, run:
mkdir -p module_bindings
spacetime generate --lang cs --out-dir module_bindings --module-path PATH-TO-MODULE-DIRECTORY
Replace PATH-TO-MODULE-DIRECTORY with the path to your SpacetimeDB module.
DbConnectionA connection to a remote database is represented by the DbConnection class. This class is generated per module and contains information about the types, tables, and reducers defined by your module.
| Name | Description |
|---|---|
| Connect to a database | Construct a DbConnection instance. |
| Advance the connection | Poll the DbConnection or run it in the background. |
| Access tables and reducers | Access the client cache, request reducer invocations, and register callbacks. |
class DbConnection
{
public static DbConnectionBuilder<DbConnection> Builder();
}
Construct a DbConnection by calling DbConnection.Builder(), chaining configuration methods, and finally calling .Build(). At a minimum, you must specify WithUri to provide the URI of the SpacetimeDB instance, and WithDatabaseName to specify the database's name or identity.
| Name | Description |
|---|---|
| WithUri method | Set the URI of the SpacetimeDB instance hosting the remote database. |
| WithDatabaseName method | Set the name or identity of the remote database. |
| WithConfirmedReads method | Enable or disable confirmed reads. |
| OnConnect callback | Register a callback to run when the connection is successfully established. |
| OnConnectError callback | Register a callback to run if the connection is rejected or the host is unreachable. |
| OnDisconnect callback | Register a callback to run when the connection ends. |
| WithToken method | Supply a token to authenticate with the remote database. |
| Build method | Finalize configuration and open the connection. |
WithUriclass DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> WithUri(Uri uri);
}
Configure the URI of the SpacetimeDB instance or cluster which hosts the remote module and database.
WithDatabaseNameclass DbConnectionBuilder
{
public DbConnectionBuilder<DbConnection> WithDatabaseName(string nameOrIdentity);
}
Configure the SpacetimeDB domain name or Identity of the remote database which identifies it within the SpacetimeDB instance or cluster.
WithConfirmedReadsclass DbConnectionBuilder
{
public DbConnectionBuilder<DbConnection> WithConfirmedReads(bool confirmedReads);
}
Configure the connection to request confirmed reads.
When enabled, the server will send query results only after they are confirmed to be durable, i.e. persisted to disk on one or more replicas depending on the replication settings of the database. When set to false, the server will send results as soon as transactions are committed in memory.
If this method is not called, the server chooses the default.
OnConnectclass DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnConnect(Action<DbConnection, Identity, string> callback);
}
Chain a call to .OnConnect(callback) to your builder to register a callback to run when your new DbConnection successfully initiates its connection to the remote database. The callback accepts three arguments: a reference to the DbConnection, the Identity by which SpacetimeDB identifies this connection, and a private access token which can be saved and later passed to WithToken to authenticate the same user in future connections.
OnConnectErrorclass DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnConnectError(Action<ErrorContext, SpacetimeDbException> callback);
}
Chain a call to .OnConnectError(callback) to your builder to register a callback to run when your connection fails.
A known bug in the SpacetimeDB Rust client SDK currently causes this callback never to be invoked. OnDisconnect callbacks are invoked instead.
OnDisconnectclass DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnDisconnect(Action<ErrorContext, SpacetimeDbException> callback);
}
Chain a call to .OnDisconnect(callback) to your builder to register a callback to run when your DbConnection disconnects from the remote database, either as a result of a call to Disconnect or due to an error.
WithTokenclass DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> WithToken(string token = null);
}
Chain a call to .WithToken(token) to your builder to provide an OpenID Connect compliant JSON Web Token to authenticate with, or to explicitly select an anonymous connection. If this method is not called or None is passed, SpacetimeDB will generate a new Identity and sign a new private access token for the connection.
Buildclass DbConnectionBuilder<DbConnection>
{
public DbConnection Build();
}
After configuring the connection and registering callbacks, attempt to open the connection.
In the interest of supporting a wide variety of client applications with different execution strategies, the SpacetimeDB SDK allows you to choose when the DbConnection spends compute time and processes messages. If you do not arrange for the connection to advance by calling one of these methods, the DbConnection will never advance, and no callbacks will ever be invoked.
| Name | Description |
|---|---|
FrameTick method | Process messages on the main thread without blocking. |
FrameTickclass DbConnection {
public void FrameTick();
}
FrameTick will advance the connection until no work remains or until it is disconnected, then return rather than blocking. Games might arrange for this message to be called every frame.
It is not advised to run FrameTick on a background thread, since it modifies dbConnection.Db. If main thread code is also accessing the Db, it may observe data races when FrameTick runs on another thread.
(Note that the SDK already does most of the work for parsing messages on a background thread. FrameTick() does the minimal amount of work needed to apply updates to the Db.)
Dbclass DbConnection
{
public RemoteTables Db;
/* other members */
}
The Db property of the DbConnection provides access to the subscribed view of the remote database's tables. See Access the client cache.
Reducersclass DbConnection
{
public RemoteReducers Reducers;
/* other members */
}
The Reducers field of the DbConnection provides access to reducers exposed by the module of the remote database. See Observe and invoke reducers.
IDbContextinterface IDbContext<DbView, RemoteReducers, ..>
{
/* methods */
}
DbConnection, EventContext, ReducerEventContext, SubscriptionEventContext and ErrorContext all implement IDbContext. IDbContext has methods for inspecting and configuring your connection to the remote database.
The IDbContext interface is implemented by connections and contexts to every module - hence why it takes DbView and RemoteReducers as type parameters.
| Name | Description |
|---|---|
IRemoteDbContext interface | Module-specific IDbContext. |
Db method | Provides access to the subscribed view of the remote database's tables. |
Reducers method | Provides access to reducers exposed by the remote module. |
Disconnect method | End the connection. |
| Subscribe to queries | Register subscription queries to receive updates about matching rows. |
| Read connection metadata | Access the connection's Identity and ConnectionId |
IRemoteDbContextEach module's module_bindings exports an interface IRemoteDbContext which inherits from IDbContext, with the type parameters DbView and RemoteReducers bound to the types defined for that module. This can be more convenient when creating functions that can be called from any callback for a specific module, but which access the database or invoke reducers, and so must know the type of the DbView or Reducers.
Dbinterface IRemoteDbContext
{
public DbView Db { get; }
}
Db will have methods to access each table defined by the module.
var conn = ConnectToDB();
// Get a handle to the User table
var tableHandle = conn.Db.User;
Reducersinterface IRemoteDbContext
{
public RemoteReducers Reducers { get; }
}
Reducers will have methods to invoke each reducer defined by the module,
plus methods for adding and removing callbacks on each of those reducers.
var conn = ConnectToDB();
// Register a callback to be run every time the SendMessage reducer is invoked
conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;
Disconnectinterface IRemoteDbContext
{
public void Disconnect();
}
Gracefully close the DbConnection. Throws an error if the connection is already closed.
| Name | Description |
|---|---|
SubscriptionBuilder type | Builder-pattern constructor to register subscribed queries. |
TypedSubscriptionBuilder type | Builder for typed query subscriptions. |
SubscriptionHandle type | Manage an active subscription. |
SubscriptionBuilder| Name | Description |
|---|---|
ctx.SubscriptionBuilder() constructor | Begin configuring a new subscription. |
OnApplied callback | Register a callback to run when matching rows become available. |
OnError callback | Register a callback to run if the subscription fails. |
Subscribe method | Finish configuration and subscribe to one or more queries. |
AddQuery method | Build a typed subscription query without writing query strings. |
SubscribeToAllTables method | Convenience method to subscribe to the entire database. |
ctx.SubscriptionBuilder()interface IRemoteDbContext
{
public SubscriptionBuilder SubscriptionBuilder();
}
Subscribe to queries by calling ctx.SubscriptionBuilder() and chaining configuration methods, then calling .Subscribe(queries).
OnAppliedclass SubscriptionBuilder
{
public SubscriptionBuilder OnApplied(Action<SubscriptionEventContext> callback);
}
Register a callback to run when the subscription is applied and the matching rows are inserted into the client cache.
OnErrorclass SubscriptionBuilder
{
public SubscriptionBuilder OnError(Action<ErrorContext, Exception> callback);
}
Register a callback to run if the subscription is rejected or unexpectedly terminated by the server. This is most frequently caused by passing an invalid query to Subscribe.
Subscribeclass SubscriptionBuilder
{
public SubscriptionHandle Subscribe(string[] querySqls);
}
Subscribe to a set of queries. queries should be an array of SQL query strings.
See the SpacetimeDB SQL Reference for information on the queries SpacetimeDB supports as subscriptions.
For typed query subscriptions, use AddQuery.
AddQueryclass SubscriptionBuilder
{
public TypedSubscriptionBuilder AddQuery<TRow>(
Func<QueryBuilder, IQuery<TRow>> build
);
}
Start a typed query subscription. Once a typed query is added, continue with typed queries on TypedSubscriptionBuilder and finish with Subscribe().
var handle = conn
.SubscriptionBuilder()
.AddQuery(q => q.From.User())
.AddQuery(q => q.From.Message())
.Subscribe();
SubscribeToAllTablesclass SubscriptionBuilder
{
public void SubscribeToAllTables();
}
Subscribe to all rows from all public tables. This method is provided as a convenience for simple clients. The subscription initiated by SubscribeToAllTables cannot be canceled after it is initiated. You should subscribe to specific queries if you need fine-grained control over the lifecycle of your subscriptions.
TypedSubscriptionBuilder| Name | Description |
|---|---|
AddQuery method | Add another typed query to the same subscription. |
Subscribe method | Subscribe to all typed queries added so far. |
AddQuery (TypedSubscriptionBuilder)class TypedSubscriptionBuilder
{
public TypedSubscriptionBuilder AddQuery<TRow>(
Func<QueryBuilder, IQuery<TRow>> build
);
}
Add another typed query. This keeps all added queries grouped under one returned SubscriptionHandle.
Subscribe (TypedSubscriptionBuilder)class TypedSubscriptionBuilder
{
public SubscriptionHandle Subscribe();
}
Subscribe to the set of typed queries that were added to the builder.
The C# SDK provides a type-safe query builder for subscriptions. You use it through SubscriptionBuilder.AddQuery(...) and TypedSubscriptionBuilder.AddQuery(...).
Typed query builders are created from generated table accessors under QueryBuilder.From.
var handle = conn
.SubscriptionBuilder()
.AddQuery(q => q.From.User())
.Subscribe();
Where / FilterEach generated table accessor supports both Where(...) and Filter(...). They are equivalent. Chaining multiple Where/Filter calls combines conditions with logical AND.
// All users
q.From.User()
// Filtered users
q.From.User().Where(u => u.Online.Eq(true))
q.From.User().Filter(u => u.Name.Neq("Anonymous"))
// Chained filters (AND semantics)
q.From.User()
.Where(u => u.Score.Gte(1000UL))
.Filter(u => u.Level.Gte(10U))
| Operator | Description | Example |
|---|---|---|
Eq | Equal to | u.Online.Eq(true) |
Neq | Not equal to | u.Name.Neq("BOT") |
Lt | Less than | u.Level.Lt(10U) |
Lte | Less than or equal to | u.Level.Lte(10U) |
Gt | Greater than | u.Score.Gt(1000UL) |
Gte | Greater than or equal to | u.Score.Gte(1000UL) |
Combine conditions with And, Or, and Not:
q.From.User().Where(u => u.Level.Gte(5U).And(u.Level.Lt(10U)))
q.From.User().Where(u => u.Online.Eq(true).Or(u.Name.Eq("Admin")))
q.From.User().Where(u => u.Banned.Eq(true).Not())
Semijoins match rows across two tables and return rows from one side:
LeftSemijoin(...) returns rows from the left side that match at least one row on the right.RightSemijoin(...) returns rows from the right side that match at least one row on the left.IxCols) and must compare one indexed column from each side with Eq.var handle = conn
.SubscriptionBuilder()
.AddQuery(q => q.From.Player()
.Where(p => p.Score.Gte(1000UL))
.LeftSemijoin(q.From.PlayerLevel(), (p, pl) => p.Id.Eq(pl.PlayerId))
.Where(p => p.Online.Eq(true)))
.AddQuery(q => q.From.Player()
.Where(p => p.Score.Gte(1000UL))
.RightSemijoin(q.From.PlayerLevel(), (p, pl) => p.Id.Eq(pl.PlayerId))
.Where(pl => pl.Level.Gte(10U)))
.Subscribe();
AddQuery accepts a builder function that returns an IQuery<TRow>. You can add multiple typed queries and subscribe once.
var handle = conn
.SubscriptionBuilder()
.AddQuery(q => q.From.User().Where(u => u.Online.Eq(true)))
.AddQuery(q => q.From.Message().Where(m => m.ChannelId.Eq(1U)))
.Subscribe();
SubscriptionHandleA SubscriptionHandle represents a subscribed query or a group of subscribed queries.
The SubscriptionHandle does not contain or provide access to the subscribed rows. Subscribed rows of all subscriptions by a connection are contained within that connection's ctx.Db. See Access the client cache.
| Name | Description |
|---|---|
IsEnded property | Determine whether the subscription has ended. |
IsActive property | Determine whether the subscription is active and its matching rows are present in the client cache. |
Unsubscribe method | Discard a subscription. |
UnsubscribeThen method | Discard a subscription, and register a callback to run when its matching rows are removed from the client cache. |
IsEndedclass SubscriptionHandle
{
public bool IsEnded;
}
True if this subscription has been terminated due to an unsubscribe call or an error.
IsActiveclass SubscriptionHandle
{
public bool IsActive;
}
True if this subscription has been applied and has not yet been unsubscribed.
Unsubscribeclass SubscriptionHandle
{
public void Unsubscribe();
}
Terminate this subscription, causing matching rows to be removed from the client cache. Any rows removed from the client cache this way will have OnDelete callbacks run for them.
Unsubscribing is an asynchronous operation. Matching rows are not removed from the client cache immediately. Use UnsubscribeThen to run a callback once the unsubscribe operation is completed.
Returns an error if the subscription has already ended, either due to a previous call to Unsubscribe or UnsubscribeThen, or due to an error.
UnsubscribeThenclass SubscriptionHandle
{
public void UnsubscribeThen(Action<SubscriptionEventContext>? onEnded);
}
Terminate this subscription, and run the onEnded callback when the subscription is ended and its matching rows are removed from the client cache. Any rows removed from the client cache this way will have OnDelete callbacks run for them.
Returns an error if the subscription has already ended, either due to a previous call to Unsubscribe or UnsubscribeThen, or due to an error.
Identityinterface IDbContext
{
public Identity? Identity { get; }
}
Get the Identity with which SpacetimeDB identifies the connection. This method returns null if the connection was initiated anonymously and the newly-generated Identity has not yet been received, i.e. if called before the OnConnect callback is invoked.
ConnectionIdinterface IDbContext
{
public ConnectionId ConnectionId { get; }
}
Get the ConnectionId with which SpacetimeDB identifies the connection.
IsActiveinterface IDbContext
{
public bool IsActive { get; }
}
true if the connection has not yet disconnected. Note that a connection IsActive when it is constructed, before its OnConnect callback is invoked.
EventContextAn EventContext is an IDbContext augmented with an Event property. EventContexts are passed as the first argument to row callbacks OnInsert, OnDelete and OnUpdate.
| Name | Description |
|---|---|
Event property | Enum describing the cause of the current row callback. |
Db property | Provides access to the client cache. |
Reducers property | Allows requesting reducers run on the remote database. |
Event record | Possible events which can cause a row callback to be invoked. |
Eventclass EventContext {
public readonly Event<Reducer> Event;
/* other fields */
}
The Event contained in the EventContext describes what happened to cause the current row callback to be invoked.
Dbclass EventContext {
public RemoteTables Db;
/* other fields */
}
The Db property of the context provides access to the subscribed view of the remote database's tables. See Access the client cache.
Reducersclass EventContext {
public RemoteReducers Reducers;
/* other fields */
}
The Reducers property of the context provides access to reducers exposed by the remote module. See Observe and invoke reducers.
Event| Name | Description |
|---|---|
Reducer variant | A reducer ran in the remote database. |
SubscribeApplied variant | A new subscription was applied to the client cache. |
UnsubscribeApplied variant | A previous subscription was removed from the client cache after a call to Unsubscribe. |
SubscribeError variant | A previous subscription was removed from the client cache due to an error. |
UnknownTransaction variant | A transaction ran in the remote database, but was not attributed to a known reducer. |
ReducerEvent record | Metadata about a reducer run. Contained in a Reducer event and ReducerEventContext. |
Status record | Completion status of a reducer run. |
Reducer record | Module-specific generated record with a variant for each reducer defined by the module. |
Reducerrecord Event<R>
{
public record Reducer(ReducerEvent<R> ReducerEvent) : Event<R>;
}
Event when we are notified that a reducer ran in the remote database. The ReducerEvent contains metadata about the reducer run, including its arguments and termination Status.
This event is passed to row callbacks resulting from modifications by the reducer.
SubscribeAppliedrecord Event<R>
{
public record SubscribeApplied : Event<R>;
}
Event when our subscription is applied and its rows are inserted into the client cache.
This event is passed to row OnInsert callbacks resulting from the new subscription.
UnsubscribeAppliedrecord Event<R>
{
public record UnsubscribeApplied : Event<R>;
}
Event when our subscription is removed after a call to SubscriptionHandle.Unsubscribe or SubscriptionHandle.UnsubscribeTthen and its matching rows are deleted from the client cache.
This event is passed to row OnDelete callbacks resulting from the subscription ending.
SubscribeErrorrecord Event<R>
{
public record SubscribeError(Exception Exception) : Event<R>;
}
Event when a subscription ends unexpectedly due to an error.
This event is passed to row OnDelete callbacks resulting from the subscription ending.
UnknownTransactionrecord Event<R>
{
public record UnknownTransaction : Event<R>;
}
Event when we are notified of a transaction in the remote database which we cannot associate with a known reducer. This may be an ad-hoc SQL query or a reducer for which we do not have bindings.
This event is passed to row callbacks resulting from modifications by the transaction.
ReducerEventrecord ReducerEvent<R>(
Timestamp Timestamp,
Status Status,
Identity CallerIdentity,
ConnectionId? CallerConnectionId,
U128? EnergyConsumed,
R Reducer
)
A ReducerEvent contains metadata about a reducer run.
Statusrecord Status : TaggedEnum<(
Unit Committed,
string Failed,
Unit OutOfEnergy
)>;
| Name | Description |
|---|---|
Committed variant | The reducer ran successfully. |
Failed variant | The reducer errored. |
OutOfEnergy variant | The reducer was aborted due to insufficient energy. |
CommittedThe reducer returned successfully and its changes were committed into the database state. An Event.Reducer passed to a row callback must have this status in its ReducerEvent.
FailedThe reducer returned an error, panicked, or threw an exception. The record payload is the stringified error message. Formatting of the error message is unstable and subject to change, so clients should use it only as a human-readable diagnostic, and in particular should not attempt to parse the message.
OutOfEnergyThe reducer was aborted due to insufficient energy balance of the module owner.
ReducerThe module bindings contains an record Reducer with a variant for each reducer defined by the module. Each variant has a payload containing the arguments to the reducer.
ReducerEventContextA ReducerEventContext is an IDbContext augmented with an Event property. ReducerEventContexts are passed as the first argument to reducer callbacks.
| Name | Description |
|---|---|
Event property | ReducerEvent containing reducer metadata. |
Db property | Provides access to the client cache. |
Reducers property | Allows requesting reducers run on the remote database. |
Eventclass ReducerEventContext {
public readonly ReducerEvent<Reducer> Event;
/* other fields */
}
The ReducerEvent contained in the ReducerEventContext has metadata about the reducer which ran.
Dbclass ReducerEventContext {
public RemoteTables Db;
/* other fields */
}
The Db property of the context provides access to the subscribed view of the remote database's tables. See Access the client cache.
Reducersclass ReducerEventContext {
public RemoteReducers Reducers;
/* other fields */
}
The Reducers property of the context provides access to reducers exposed by the remote module. See Observe and invoke reducers.
SubscriptionEventContextA SubscriptionEventContext is an IDbContext. Unlike the other context types, SubscriptionEventContext doesn't have an Event property. SubscriptionEventContexts are passed to subscription OnApplied and UnsubscribeThen callbacks.
| Name | Description |
|---|---|
Db property | Provides access to the client cache. |
Reducers property | Allows requesting reducers run on the remote database. |
Dbclass SubscriptionEventContext {
public RemoteTables Db;
/* other fields */
}
The Db property of the context provides access to the subscribed view of the remote database's tables. See Access the client cache.
Reducersclass SubscriptionEventContext {
public RemoteReducers Reducers;
/* other fields */
}
The Reducers property of the context provides access to reducers exposed by the remote module. See Observe and invoke reducers.
ErrorContextAn ErrorContext is an IDbContext augmented with an Event property. ErrorContexts are to connections' OnDisconnect and OnConnectError callbacks, and to subscriptions' OnError callbacks.
| Name | Description |
|---|---|
Event property | The error which caused the current error callback. |
Db property | Provides access to the client cache. |
Reducers property | Allows requesting reducers run on the remote database. |
Eventclass SubscriptionEventContext {
public readonly Exception Event;
/* other fields */
}
Dbclass ErrorContext {
public RemoteTables Db;
/* other fields */
}
The Db property of the context provides access to the subscribed view of the remote database's tables. See Access the client cache.
Reducersclass ErrorContext {
public RemoteReducers Reducers;
/* other fields */
}
The Reducers property of the context provides access to reducers exposed by the remote database. See Observe and invoke reducers.
All IDbContext implementors, including DbConnection and EventContext, have .Db properties, which in turn have methods for accessing tables in the client cache.
Each table defined by a module has an accessor method on this .Db property, generated from the table accessor name using C# naming conventions (for example, player_score becomes PlayerScore). The table accessor methods return table handles which inherit from RemoteTableHandle and have methods for searching by index.
| Name | Description |
|---|---|
RemoteTableHandle | Provides access to subscribed rows of a specific table within the client cache. |
| Unique constraint index access | Seek a subscribed row by the value in its unique or primary key column. |
| BTree index access | Seek subscribed rows by the value in its indexed column. |
RemoteTableHandleImplemented by all table handles.
| Name | Description |
|---|---|
Row type parameter | The type of rows in the table. |
Count property | The number of subscribed rows in the table. |
Iter method | Iterate over all subscribed rows in the table. |
OnInsert callback | Register a callback to run whenever a row is inserted into the client cache. |
OnDelete callback | Register a callback to run whenever a row is deleted from the client cache. |
OnUpdate callback | Register a callback to run whenever a subscribed row is replaced with a new version. |
Rowclass RemoteTableHandle<EventContext, Row>
{
/* members */
}
The type of rows in the table.
Countclass RemoteTableHandle
{
public int Count;
}
The number of rows of this table resident in the client cache, i.e. the total number which match any subscribed query.
Iterclass RemoteTableHandle
{
public IEnumerable<Row> Iter();
}
An iterator over all the subscribed rows in the client cache, i.e. those which match any subscribed query.
OnInsertclass RemoteTableHandle
{
public delegate void RowEventHandler(EventContext context, Row row);
public event RowEventHandler? OnInsert;
}
The OnInsert callback runs whenever a new row is inserted into the client cache, either when applying a subscription or being notified of a transaction. The passed EventContext contains an Event which can identify the change which caused the insertion, and also allows the callback to interact with the connection, inspect the client cache and invoke reducers. Newly registered or canceled callbacks do not take effect until the following event.
See the quickstart for examples of registering and unregistering row callbacks.
OnDeleteclass RemoteTableHandle
{
public delegate void RowEventHandler(EventContext context, Row row);
public event RowEventHandler? OnDelete;
}
The OnDelete callback runs whenever a previously-resident row is deleted from the client cache. Newly registered or canceled callbacks do not take effect until the following event.
See the quickstart for examples of registering and unregistering row callbacks.
OnUpdateclass RemoteTableHandle
{
public delegate void RowEventHandler(EventContext context, Row row);
public event RowEventHandler? OnUpdate;
}
The OnUpdate callback runs whenever an already-resident row in the client cache is updated, i.e. replaced with a new row that has the same primary key. The table must have a primary key for callbacks to be triggered. Newly registered or canceled callbacks do not take effect until the following event.
This also applies to query builder views over tables with primary keys.
See the quickstart for examples of registering and unregistering row callbacks.
For each unique constraint on a table, its table handle has a property which is a unique index handle and whose name is the unique column name. This unique index handle has a method .Find(Column value). If a Row with value in the unique column is resident in the client cache, .Find returns it. Otherwise it returns null.
Given the following module-side User definition:
[Table(Accessor = "User", Public = true)]
public partial class User
{
[Unique] // Or [PrimaryKey]
public Identity Identity;
..
}
a client would lookup a user as follows:
User? FindUser(RemoteTables tables, Identity id) => tables.User.Identity.Find(id);
For each btree index defined on a remote table, its corresponding table handle has a property which is a btree index handle and whose name is the name of the index. This index handle has a method IEnumerable<Row> Filter(Column value) which will return Rows with value in the indexed Column, if there are any in the cache.
Given the following module-side Player definition:
[Table(Accessor = "Player", Public = true)]
public partial class Player
{
[PrimaryKey]
public Identity id;
[SpacetimeDB.Index.BTree(Accessor = "Level")]
public uint level;
..
}
a client would count the number of Players at a certain level as follows:
int CountPlayersAtLevel(RemoteTables tables, uint level) => tables.Player.Level.Filter(level).Count();
All IDbContext implementors, including DbConnection and EventContext, have a .Reducers property, which in turn has methods for invoking reducers defined by the module and registering callbacks on it.
Each reducer defined by the module has three methods on the .Reducers:
set_name. This requests that the module run the reducer.on_, like on_set_name. This registers a callback to run whenever we are notified that the reducer ran, including successfully committed runs and runs we requested which failed. This method returns a callback id, which can be passed to the callback remove method.remove_on_, like remove_on_set_name. This cancels a callback previously registered via the callback registration method.IdentityA unique public identifier for a client connected to a database. See the module docs for more details.
ConnectionIdAn opaque identifier for a client connection to a database, intended to differentiate between connections from the same Identity.
See the module docs for more details.
TimestampA point in time, measured in microseconds since the Unix epoch. See the module docs for more details.
TaggedEnumA tagged union type. When defining TaggedEnum types in a module, use partial record, not partial class.
See the module docs for more details.