Relatude Help

Relatude.DB

A practical manual

Relatude.DB is an open-source, C#-native object-oriented graph database with integrated full-text (BM25) search, vector/semantic search, file storage, faceting and a built-in admin UI. It runs in-process or server-hosted, and targets .NET 10+.

This manual shows how to shape your data, write it and get it back out, and covers the tools and services around the engine. It uses one running example domain, a venue-and-events platform, so each concept builds on the last.

  • 1 The mental model — Everything in Relatude.DB is a node. A node has:
  • 2 Your first node type — The three namespaces a model file usually imports:
  • 3 Scalar properties and their attributes — A property needs no attribute: the engine infers a sensible property model from its CLR type. Add an attribute when you want indexing, validation, faceting or search. The most important flag is Indexed. A property must…
  • 4 Marker properties — A marker attribute maps a member to a value the store keeps for every node. The member is not a property of its own: the store fills it in when it reads the node, and other attributes on it are ignored. Use each marker…
  • 5 Geo coordinates — GeoCoordinate (in Relatude.DB.Common) is a WGS84 latitude and longitude. It is a small readonly struct, and an indexed GeoCoordinate property answers radius queries from a spatial index.
  • 6 Files — FileValue (in Relatude.DB.Common) refers to a file in the store's file storage: local disk, Azure blob storage and others, configured separately. The node holds the reference, and the bytes live in the storage.
  • 7 Embedded data — Embedded objects are owned values. They are stored inside the parent node, have no identity in the graph, and are deleted with it. Use them for data that only makes sense with its parent: opening hours on a venue, line…
  • 8 References — lightweight pointers — A reference stores the id of another node on this node. It points one way: it is cheap to store and to set, and the target does not know about it.
  • 9 Relations — the graph edges — A relation is an indexed edge between two nodes, readable from both ends: relating A to B also relates B to A. Relations can be traversed, filtered and counted without loading the nodes. Relations are not foreign keys…
  • 10 Choosing between relation, reference and embedded — This is the modelling choice you make most often.
  • 11 The complete example model — Here is the whole running domain in one place. Parts II and III query this model. Two details follow from §4. Names are ordinary properties marked DisplayName = true, so you set, index and query them like any other. Slug…
  • 12 Registering the model & the admin UI
  • 13 Create, insert, update, delete — In the examples, db is ctx.Database, the NodeStore. Create<T>() makes a node object in memory and gives it a new id. Nothing is stored until you insert it:
  • 14 Relating nodes — Name a relation by one of its relation properties, as a lambda, and pass the two nodes or their ids:
  • 15 Transactions — A transaction groups writes so they succeed or fail together. Transaction has the same write methods as NodeStore, with the same OrFail, IfExists and Force… variants. Nothing is written until you call Execute:
  • 16 Older versions of a node — Every write appends the whole node to the transaction log, linked to the version before it. So the log is a version history, and FindOlderVersions reads it, newest first:
  • 17 Uploading files — Insert the node first: an upload writes to a stored node. It stores the bytes and sets the FileValue on the node, so no Update is needed afterwards.
  • 18 URLs and the URL manager — A URL is never stored. Each node keeps a short address, the slug in its [AddressProperty], and the store's URL manager builds URLs from addresses and live data: the node's place in a tree, its culture, the host of the…
  • 19 Query anatomy — You build a query with the IQueryOfNodes<TNode, TInclude> builder and run it with Execute():
  • 20 Filtering with Where — Chained Where calls are combined with AND:
  • 21 Text and semantic search — Relatude.DB has BM25 keyword search and vector (semantic) search built in. semanticRatio blends them: 0.0 is keyword only, 1.0 is vector only, and values between give a hybrid.
  • 22 Geo queries — A radius filter is an ordinary Where clause. GeoCoordinate.IsWithin(center, meters) uses the property's index when it has Indexed = true:
  • 23 Relation filters — Filter nodes by what they are related to, without loading either side:
  • 24 Eager loading: Include and Preload — Include and Preload load related nodes with the result, in the same round trip. Use Include for relations and Preload for Reference<T> and References<T> properties, which yield nothing from foreach unless preloaded…
  • 25 Graph traversal and shortest path — Both work over relations, not references or embedded data.
  • 26 Sorting, paging and result sets — OrderByMeta sorts by the node's own CreatedUtc or ChangedUtc, on any type, whether or not the class maps them (Querying by the node's own dates). To sort by several keys, chain OrderBy calls. Each sort keeps the order…
  • 27 Aggregates — Count() on the builder answers from the indexes and loads no nodes, so it is much cheaper than Execute().Count(). It returns int; the whole-store counters db.Count() and db.Count<T>() return long. For an average, a…
  • 28 Faceted search — Facets count the matching nodes per value or range of a property: what a filter sidebar shows. Call .Facets() to switch the builder to facet mode, then name the facets:
  • 29 Cultures, visibility and scoped stores — A query reads through a context: a culture, a user, and what counts as visible. Set it per query:
  • 30 Pitfalls and gotchas — Modelling Reference/References yield nothing from foreach unless preloaded. Use .Get(), .TryGet(out …) or .Preload(...). This makes accidental N+1 loads impossible. Never construct or assign a NodeMeta. Default it to…
  • 31 The command line tool — relatude is the command line tool for Relatude.DB. It creates new applications, and it works on an existing database and datamodel from the outside, without your application running. Use it to look at the model, run a…
  • 32 Logs — recording what the application does — A database keeps activity logs about itself: queries, transactions, actions, tasks, and its metrics every second. You switch them on and off on the admin UI's Activity page. The Logs page is for logs of your own, about…
  • 33 GraphQL endpoints — A database can answer GraphQL, with a schema generated from the datamodel. Each node type you expose becomes a GraphQL type with a field per property, and root fields that fetch a node by id or page through nodes with…
  • 34 AI services — db.Services gives your code four AI services. Each goes through a provider configured for the database, so your code uses the installation's account and needs no vendor keys of its own.
  • 35 Relatude Services — Relatude Services is a hosted service run by Relatude at https://services.relatude.com. It puts the third-party services an application tends to need behind one account: language models, image AI, text from files…
  • 36 Background tasks and the scheduler — Work that does not belong in a transaction runs in the database's task queue: text indexing, embeddings, backups, log rewrites, and tasks your own code queues with EnqueueTask. The scheduler runs jobs through that queue…
  • Where to look when this manual runs out — Relatude.DB is open source, and its code is small and well commented. When this manual does not answer a question, or does not match your build, start with these files in the repository: