The .NET SDK translates datatypes native to SurrealQL into either datatypes native to .NET, or a custom implementation. This document describes all datatypes, and links to their respective documentation.
Datatype | Kind | Documentation | |
---|---|---|---|
String | Native | String | |
Number | Native | Any number type, e.g. Int32 ,Single | |
Float | Native | Any number type, e.g. Int32 ,Single | |
Bool | Native | Boolean | |
Null | Native | null | |
None | Custom | None | |
Array | Native | Any | |
Object | Native | Any | |
Datetime | Native | DateTime orDateOnly | |
Binary | Native | byte[] | |
Uuid | Native | Guid | |
Duration | Native | TimeSpan orTimeOnly | |
Decimal | Native | Decimal | |
Geometry | via Microsoft.Spatial |
| |
Table | Native | String | |
RecordId | Custom | RecordId |
None
The None
type is a custom type that represents the absence of a value.
Signaturepublic readonly struct None { }
None
Constructingvar none = new None(); // Change the value of a record to None var myRecord = new MyRecord(); myRecord.Value = new None();
RecordId
When you receive a RecordId back from SurrealDB, it will always be represented as a RecordId
. The class holds Table
and Id
fields, representing the table name, and a unique identifier for the record on that table.
Signaturepublic class RecordId { public string Table { get; } public T DeserializeId<T>(); // ... The rest is omitted for brevity }
The RecordId
is a non-generic class, allowing you to extract the Id
field by providing the output type via the DeserializeId
method. This can helpful when the RecordId
is used in a generic context, for when you store the Id
as an Object or an Array for example.
For cases where you are aware of the type of the Id
field, you can use the generic version of RecordId
to avoid the need for manual deserialization.
Signature with genericspublic class RecordIdOf<T> : RecordId { public T Id { get; } }
The default type of an Id
in SurrealDB being a string
, you can choose to use the default provided type RecordIdOfString
.
Default RecordIdpublic class RecordIdOfString : RecordIdOf<string> { // The available properties, inherited from `RecordId` and `RecordIdOf<string>` public string Table { get; } public string Id { get; } }
RecordId
The simplest and most common way to construct a RecordId
is with a tuple (table, id)
.
Constructing// Table is "person" // Unique identifier on the table is "john" RecordId personId = ("person", "john"); // or var personId = (RecordId)("person", "john");
This tuple is implicitly converted into a RecordId
object. You can use it with all SDK methods:
Using RecordIdawait db.Select<Person>(("person", "john")); await db.Delete(("person", "john"));
You are not exclusively limited to the string
type for the Id
part. Several overloads exist for different id
types:
ConstructingRecordId rid1 = ("person", "alice"); // string RecordId rid2 = ("person", 123); // int RecordId rid3 = ("person", 123L); // long RecordId rid4 = ("person", (short)5); // short RecordId rid5 = ("person", (byte)7); // byte RecordId rid6 = ("person", Guid.NewGuid()); // Guid
The .NET SDK handles serialization and deserialization of the Table
and Id
parts in Record Id. The serialization is done automatically when sending data to the server. However, deserialization may need to be done manually according to the data type of the Id
field. Below are some examples:
Simple record idRecordId rid = ("person", "john"); string table = rid.Table; // "person" string id = rid.DeserializeId<string>(); // "john"
Record id with simple data type (other than string)RecordId rid = ("table", 42); string table = rid.Table; // "table" int id = rid.DeserializeId<int>(); // 42
Record id with complex data typesvar rid = new RecordIdOf<CityId>("table", new CityId { City = "London" }); var id = rid.DeserializeId<CityId>(); // CityId { City = "London" } var rid = new RecordIdOf<(string, int)>("table", ("London", 42)); var id = rid.DeserializeId<(string, int)>(); // ("London", 42)
If you need to send back a Record Id in string format, you can do so with the StringRecordId
class.
We do not implement the parsing of Record Ids in the .NET SDK, as that would mean that we need to be able to parse any SurrealQL value, which comes with a cost. Instead you can send it over as a string with StringRecordId
, allowing the server to handle the parsing.
Signaturepublic class StringRecordId { public string Value { get; } }
StringRecordId
Constructing// Table is "person" // Unique identifier on the table is "john" var rid = new StringRecordId("person:john"); // Alternatively, a StringRecordId can be inferred explicitly from a string var rid = (StringRecordId)"person:john"; await client.Select<Person>((StringRecordId)"person:john");
RecordIdOfString
For string-based identifiers, you can also use the specialized type RecordIdOfString:
Using RecordIdOfStringvar rid = new RecordIdOfString("person", "john"); // or Console.WriteLine(rid.Table); // "person" Console.WriteLine(rid.Id); // "john"
RecordIdOf<T>
For complex or structured identifiers, use the generic type RecordIdOf<T>:
Using RecordIdOf<T>public class CityId { public string City { get; set; } = string.Empty; } var rid = new RecordIdOf<CityId>("city", new CityId { City = "London" });
This enables strongly-typed IDs that map directly to your domain objects.
If your model class inherits from Record, it will automatically include an Id property of type RecordId
.
Inheriting from Recordpublic class Person : Record { public string Name { get; set; } = string.Empty; } // Example usage var person = new Person { Name = "Alice" }; Console.WriteLine(person.Id); // RecordId ("person", "…")
The SDK supports attributes for serialization and deserialization.
Use CborProperty to map C# properties to SurrealDB fields:
Using CborProperty[CborProperty("first_name")] public string FirstName { get; set; } = string.Empty;
Use RecordIdJsonConverter to indicate that a property should be serialized as a RecordId reference to another table:
Using RecordIdJsonConverter[RecordIdJsonConverter("payment_details")] public RecordId? PaymentDetails { get; set; } [RecordIdJsonConverter("payment_details")] public RecordId? PaymentDetails { get; set; }
You can combine both attributes on the same property:
Combining attributes[CborProperty("payment_details")] [RecordIdJsonConverter("payment_details")] public RecordId? PaymentDetails { get; set; }