YndigoBlue · Velocity Framework

Cross-vendor .NET database access — one API to rule them all

Write your data layer once. Deploy it against SQL Server, PostgreSQL, MySQL, Oracle, Teradata, DB2 or SQLite with zero code changes.

OrderRepository.cs
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Model;
using YndigoBlue.Velocity.Attributes;

public class Order
{
    [VelocityField("order_id")]   public int    OrderId   { get; set; }
    [VelocityField("customer")]   public string Customer  { get; set; }
    [VelocityField("total")]      public decimal Total    { get; set; }
    [VelocityField("created_at")] public DateTime Created { get; set; }

    public static Table Table { get; } = Datastore.Schema["order"];
}

// Type-safe query — no raw SQL, no strings
var query = new Query()
    .Select([Order.Table["order_id"],
             Order.Table["customer"],
             Order.Table["total"]])
    .From(Order.Table)
    .Where(new Criterion<decimal>(Order.Table["total"], 100m, CriterionType.GreaterThan))
    .OrderBy(Order.Table["created_at"], OrderClauseType.Descending);

// Works identically on every supported database
using var manager = new Manager(connection);
IList<Order> orders = manager.Retrieve(query)
                              .BindResults<Order>(BindingType.Attribute);
7
Supported Databases
1
Unified API
.NET 10
Target Framework
100%
Type-Safe Queries
Capabilities

Everything your data layer needs

Velocity handles the complexity of cross-database access so you can focus on your application, not the plumbing.

Cross-Vendor Compatibility

Connect to SQL Server, PostgreSQL, MySQL, Oracle, Teradata, IBM DB2 and SQLite through one consistent API. Switch vendors by changing a single configuration line.

Single Codebase

Write your data access layer once with no vendor-specific SQL dialects or separate repositories. One clean, maintainable codebase that runs everywhere.

Type-Safe Query Builder

Compose queries with a fluent, type-safe API — no raw SQL strings anywhere in your application. Criteria, joins, aggregates and ordering all handled at the .NET layer.

Declarative Schema Management

Define your database schema in XML, JSON or YAML and load it with a few lines of code. Version, migrate and refresh schemas across environments with confidence.

Batch Data Import

Import large datasets efficiently with Velocity's unified batch API. Handles bulk inserts, upserts and transactions consistently across all supported vendors.

Geospatial Support

First-class support for Geography and Geometry types. Store and query spatial data using familiar .NET types — no vendor-specific spatial SQL required.

Compatibility

Runs on every major database

Whether your organisation standardises on an enterprise warehouse or a lightweight embedded database, Velocity has you covered.

SQL Server
PostgreSQL
MySQL
Oracle
Teradata
IBM DB2
SQLite
Code

Clean. Expressive. Familiar.

Velocity's API feels natural to any .NET developer. Attribute-based model mapping, a composable query builder and strongly-typed results — no raw SQL, ever.

using YndigoBlue.Velocity.Attributes;
using YndigoBlue.Velocity.Model;

/// <summary>
/// Decorate properties with [VelocityField] to map snake_case columns
/// to PascalCase .NET properties automatically.
/// </summary>
public class Product
{
    [VelocityField("product_id")]
    public int ProductId { get; set; }

    [VelocityField("product_name")]
    public string Name { get; set; }

    [VelocityField("unit_price")]
    public decimal Price { get; set; }

    [VelocityField("category")]
    public string Category { get; set; }

    [VelocityField("created_at")]
    public DateTime CreatedAt { get; set; }

    // Resolved once from the schema — reuse this static reference everywhere
    public static Table Table { get; } = Datastore.Schema["product"];
}
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Model;

// Manager is the entry point — handles connection lifecycle and pooling
using var manager = new Manager(connection);

// Compose a type-safe query — no raw SQL strings in application code
// Multiple criteria are combined in an array with BooleanItem connectors
var query = new Query()
    .Select([Product.Table["product_id"],
             Product.Table["product_name"],
             Product.Table["unit_price"],
             Product.Table["category"]])
    .From(Product.Table)
    .Where([
        new Criterion<decimal>(Product.Table["unit_price"], 50.00m, CriterionType.GreaterThan),
        new BooleanItem(BooleanType.And),
        new Criterion<string>(Product.Table["category"], "Electronics")
    ])
    .OrderBy(Product.Table["unit_price"], OrderClauseType.Descending);

// BindResults maps each result row to a typed object via [VelocityField]
IList<Product> products = manager
    .Retrieve(query)
    .BindResults<Product>(BindingType.Attribute);

// Update a record — criterion is passed to the constructor; use typed Set methods
var update = new Update(Product.Table,
    new Criterion<int>(Product.Table["product_id"], 42));
update.SetFieldDecimal("unit_price", 45.00m);
manager.UpdateRecords(update);
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Model;

var orderTable   = Datastore.Schema["order"];
var customerTable = Datastore.Schema["customer"];

// Aggregates — count, sum, avg, min, max
var revenueExpr = new Expression(
    "total_revenue",
    new Aggregate(AggregateType.Sum, orderTable["amount"]));

var countExpr = new Expression(
    "order_count",
    new Aggregate(AggregateType.Count, orderTable["order_id"]));

// Cross-table join with grouping
var query = new Query()
    .Select([customerTable["name"], revenueExpr, countExpr])
    .From(new Join(
        orderTable,  orderTable["customer_id"],
        customerTable, customerTable["customer_id"]))
    .GroupBy(customerTable["name"])
    .OrderBy(revenueExpr, OrderClauseType.Descending);

// Bind to a dedicated result model
IList<CustomerRevenue> topCustomers = manager
    .Retrieve(query)
    .BindResults<CustomerRevenue>(BindingType.Attribute);
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Enums;
using YndigoBlue.Velocity.Model;

// Load schema from a versioned XML file and cache it globally
Datastore.Schema = manager.ReadSchemaFromFile("Config/myapp-v3.xml", ConfigType.Xml);

// Verify the live database matches — roll back to the previous version if not
Schema liveSchema = manager.LoadSchema("myapp");
if (!liveSchema.Equals(Datastore.Schema))
{
    Datastore.Schema = manager.ReadSchemaFromFile("Config/myapp-v2.xml", ConfigType.Xml);
}

// Deploy a schema update (e.g. new columns, new tables) in a transaction
string newSchemaXml = File.ReadAllText("Config/myapp-v4.xml");
Datastore.Schema = manager.ReadSchema(newSchemaXml, ConfigType.Xml);

manager.BeginTransaction();
manager.UpdateSchema(Datastore.Schema);
manager.CommitTransaction();

// Rebuild the schema from scratch — drops and recreates all tables
manager.BuildSchema(Datastore.Schema, overwrite: true);
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Model;

// ── CSV import ──
// ImportConfig takes the target table, date format, and whether to retain identity values from file
var config = new ImportConfig(Product.Table, DateFormatType.Iso, keepIdentity: true);
manager.ImportData(Product.Table, "data/products.csv", config);

// ── Export a full schema to CSV (one file per table) ──
manager.ExportSchema(
    Datastore.Schema,
    ConfigType.Xml,
    outputDirectory: "data/export/",
    new ExportConfig(DateFormatType.Iso),
    includeSchema: false);

// ── Insert a single record using typed field setters ──
var record = new Record(Product.Table);
record.SetFieldLong("product_id", 1001);
record.SetFieldVarChar("product_name", "Widget Pro");
record.SetFieldDecimal("unit_price", 49.99m);
record.SetFieldBoolean("in_stock", true);
record.SetFieldDateTime("created_at", DateTime.UtcNow);
manager.AddRecord(record);
using YndigoBlue.Velocity.Engine;
using YndigoBlue.Velocity.Enums;
using YndigoBlue.Velocity.Functions;
using YndigoBlue.Velocity.Model;

// ── Store a geography value ──
Geography london = GeospatialUtils.GeographyFromText("POINT (-0.1276 51.5074)");

var record = new Record(Location.Table);
record.SetFieldVarChar("name", "London");
record.SetFieldGeography("coordinates", london);
manager.AddRecord(record);

// ── Proximity query: find all locations within 50 km of a reference point ──
Geography origin = GeospatialUtils.GeographyFromText("POINT (-1.8904 52.4862)");

// SpatialDistance computes ST_Distance between the column and the reference point
var distanceFn = new SpatialDistance(
    Location.Table["coordinates"],
    origin,
    UnitOfMeasure.Kilometer);

// Wrap in an Expression so it can appear in both SELECT and WHERE
var distanceExpr = new Expression("distance_km", distanceFn);

var query = new Query()
    .Select([Location.Table["name"], Location.Table["coordinates"], distanceExpr])
    .From(Location.Table)
    .Where(new Criterion<double>(distanceExpr, 50.0, CriterionType.LessThan))
    .OrderBy(distanceExpr, OrderClauseType.Ascending);

IList<Location> nearby = manager
    .Retrieve(query)
    .BindResults<Location>(BindingType.Attribute);
Architecture

One abstraction layer, every database

Velocity translates your type-safe queries into the correct vendor dialect at runtime. Your application code never touches vendor-specific SQL.

Your .NET Application C# · ASP.NET · Azure Functions Velocity API Velocity Framework Type-Safe Query Builder Attribute Mapper · BindResults Schema Manager Batch Import · Geospatial Native drivers IBM DB2 MySQL PostgreSQL Oracle SQL Server SQLite Teradata

Ready to get started?

The full Velocity Framework documentation covers installation, connection configuration, schema management, query building, joins, aggregates, geospatial data, and batch import.