Cohesive Systems logoCOHESIVE SYSTEMS

Search Cohesive Systems

Ready

Search Cohesive Systems

Find product pages, building blocks, technical articles, and graph definitions.

Building Blocks

Cohesive.Relations

Define relationships, projections, and queries in familiar C#, then use them across objects, databases, search indexes, and composed data sources.

Core Idea

Applications constantly connect facts. A load refers to a customer. An order contains lines. A search result combines entity state with related names, totals, and status. The code that performs this work often ends up split among repository methods, LINQ expressions, SQL, API calls, and mapping profiles.

Cohesive.Relations gives those relationships and derivations one structured definition. A relation describes what can be derived from supplied input. A query describes an independently invoked request for named results.

The normal authoring surface uses typed C# expressions:

var author = RelationQuery.Expression();
var loads = author.Source<Load>();
 
var customers = author.Traverse<Load, Customer>(
    loads,
    load => load.CustomerId);
 
var searchDocuments = author.Project(
    customers,
    (Load load, Customer customer) => new LoadSearchDto
    {
        Id = load.Id,
        Status = load.Status,
        CustomerName = customer.Name
    });
 
var loadSearch = searchDocuments.BuildRelation(dto => dto.Id);

Traverse declares that Load.CustomerId refers to a Customer. Project describes the result. The definition does not choose a database, table, container, index, or join algorithm, so the same business meaning can be evaluated from supplied objects, acquired from registered sources, or compiled for a capable backend.

Getting Started

The guided walkthrough starts with ordinary CLR types and one supplied Load. It authors a typed projection, evaluates it without configuring storage, materializes a DTO, and then adds a Customer relationship.

Open the Getting Started guide →

A Small Mental Model

Relations work with a few explicit parts:

Source

Question it answers
Which kind of fact is available?
Load search example
Loads and Customers are logical sources; their physical locations are configured later.

Relationship

Question it answers
How does one fact refer to another?
Load search example
Load.CustomerId addresses one Customer identity.

Derivation

Question it answers
How are available facts filtered, combined, or reshaped?
Load search example
A Load and Customer establish one LoadSearchDto.

Relation

Question it answers
What result can be derived for supplied input?
Load search example
Given a Load, derive its enriched search document.

Query

Question it answers
What independently requested results should be returned?
Load search example
Find open loads, order them, page them, and return a total.

Evaluation

Question it answers
What is requested on this invocation?
Load search example
Supply one Load or select particular query outputs and runtime parameters.

A fact is represented as a shaped value or observation. It may begin as a CLR object, entity snapshot, database row, API response, cached value, or materialized document. Relations keeps its semantic role stable while adapters handle the physical representation.

Why Make the Upfront Investment?

A POCO projection or repository method is often enough for one screen. As the same relationship appears in APIs, indexes, reports, integrations, and background work, each implementation can develop its own loading behavior and assumptions. A Cohesive relation makes that shared relational program explicit.

Structured relational model

What it gives you
Sources, relationships, filters, projections, ordering, paging, and aggregations have defined roles instead of being embedded in unrelated mapping and repository code.

One definition for adjacent tooling

What it gives you
The same relation can support DTO mapping, queries, dependency analysis, lineage, documentation, materialization, and future simulation or generated tests.

Exact data requirements

What it gives you
Compilation identifies the fields and related facts demanded by selected outputs, allowing adapters to avoid reading every available field.

Explicit source boundaries

What it gives you
Supplied input, database reads, search indexes, APIs, and local correlation remain visible, including their completeness and operating limits.

Structured diagnostics

What it gives you
Invalid expressions, missing facts, unsupported backend behavior, incomplete reads, and binding errors retain the definition sites and outputs they affect.

Safe derived views

What it gives you
Field dependencies and relationship paths can drive targeted materialization updates and rebuilds without maintaining a second dependency model.

Infrastructure agnostic

What it gives you
Relational meaning stays independent of a particular database or SDK. An adapter must demonstrate a valid realization of the behavior the selected result requires.

How a Relation Runs

An application evaluates a relation or query with selected outputs, parameters, and any facts it already has. The Relations execution environment compiles only what that invocation needs, matches those requirements with configured source and adapter capabilities, and then creates a physical plan.

Supplied objects can be interpreted directly. When facts must be loaded, Cohesive.Storage registrations connect logical shapes to bounded source readers. A plan can enumerate roots, batch related identities, correlate the returned facts locally, and construct the requested result. A capable backend compiler can instead produce a native query artifact for explicit application dispatch.

Produce

Author or infer

Expression C#
Structural C#
Ari and imports

Persist

Canonical documents

Relationship catalog
Relation or query
Evaluation request

Compile

Demand and evidence

Static plan
Capabilities
Placement and bindings

Interpret

Execute or explain

Native artifact
Composed evaluation
DTO, lineage, explain
Physical choices enter after the semantic documents and demand-scoped plan exist. Every derived artifact retains provenance to the canonical definition and the evidence that authorized its realization.

The evaluation result includes the rows or aggregations together with diagnostics, completeness, and source evidence. This makes a partial read or unsupported operation distinguishable from a valid empty result.

Relationships, Relations, and Queries

Use Traverse when a connection is part of the domain relation model, such as Load.CustomerId → Customer identity. The relationship retains its direction and cardinality. Use Join when the matching predicate itself is the meaning and no reusable domain relationship should be asserted.

A relation is rooted in supplied input and declares output cardinality relative to that root. It fits DTO mapping, enrichment, integration payloads, and derived documents. A query is invoked independently and can expose named row and aggregation results with filtering, ordering, and paging. Both use the same relational operators and can share logical sources and relationships.

Current operators include sources, filters, relationship traversal, explicit and valid-time joins, collection expansion, projection, distinctness, aggregation, ordering, and paging. Support is checked against the exact operators and value behavior demanded by an invocation.

Sources and Adapters

The current execution paths have intentionally different responsibilities:

Supplied and in-memory

What it does today
Evaluates canonical semantics over facts supplied by the caller or already acquired by a plan.
Important boundary
Performs no I/O and serves as the reference interpretation for conformance tests.

PostgreSQL

What it does today
Compiles supported definitions to parameterized SQL and provides an Npgsql source reader for bounded enumeration, identity batches, and predicate batches.
Important boundary
The evaluator can use the registered source reader; dispatch of a compiled native SQL artifact remains an explicit application integration.

Cosmos DB

What it does today
Compiles supported single-container queries and uses the Cosmos SDK for bounded source acquisition in composed plans.
Important boundary
Cross-container relationships use explicit reads and local correlation rather than being represented as a Cosmos array JOIN.

Elasticsearch

What it does today
Lowers supported single-index filters, projections, aggregations, ordering, paging, and mapped nested correlation into SDK request descriptors.
Important boundary
The configured mapping must prove the requested scalar and nested behavior; broader collection semantics remain unsupported.

DTO materialization

What it does today
Compiles CLR construction from canonical output rows.
Important boundary
It constructs values after evaluation and does not acquire facts or reinterpret the relation.

Adapters can preserve the same relation differently. A co-located Load and Customer may become one PostgreSQL join. The same relationship across a load store and customer store may become one bounded root read, one Customer identity batch, and local correlation.

Relation-Derived Materialized Views

Cohesive.Storage can use a compiled relation as the authority for a materialized projection model. Relations exposes the required fields, relationship paths, lineage, and dependency directions. Storage turns that evidence into an exact impact plan, obtains source changes, reevaluates affected roots, and writes a versioned target generation.

This is more precise than treating every source change as a global rebuild, while still failing safely when an incremental path cannot be proven. Rebuild scheduling, checkpoints, retries, target promotion, and change settlement remain Storage responsibilities rather than becoming query operators.

See Relation-derived materialization in Cohesive.Storage →

Where the Model Fits

Build application read models

Use one typed derivation for API responses, screens, integration payloads, and enriched DTOs.

  • Project a supplied entity into a response DTO
  • Enrich it with facts from related entities
  • Select only the fields needed by one endpoint
  • Retain provenance for each output field

Integration Boundaries

Relations

Responsibility
Own relationships, derivations, queries, compilation requirements, evaluation, completeness, and result provenance.

Storage and source adapters

Responsibility
Bind logical facts to physical sources, perform bounded acquisition, and maintain Relation-derived views.

Processes

Responsibility
Use relations for typed reads while coordinating waits, entity changes, requests, and durable workflow progress.

Entities and Transitions

Responsibility
Own authoritative business state and legal decisions; their observations can supply facts to relational programs.

Ari

Responsibility
Propose and govern inferred mappings before accepted semantics become ordinary Relations definitions.

Going Deeper

The application-facing path starts with typed expression authoring and a small supplied-object evaluation. Canonical documents, demand compilation, capability realization, placement, physical planning, completeness evidence, and explain artifacts are covered separately.

Author and evaluate the first relation →

Read about Relations internals →