OmniDataAccess 1.1.0

dotnet add package OmniDataAccess --version 1.1.0
                    
NuGet\Install-Package OmniDataAccess -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OmniDataAccess" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OmniDataAccess" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="OmniDataAccess" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OmniDataAccess --version 1.1.0
                    
#r "nuget: OmniDataAccess, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OmniDataAccess@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OmniDataAccess&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=OmniDataAccess&version=1.1.0
                    
Install as a Cake Tool

OmniDataAccess

Meta-package that bundles OmniDataAccess.Core, OmniDataAccess.SqlDatabases and OmniDataAccess.NoSqlDatabases into a single dependency. Also ships IHybridCacheManager — a cache-aside implementation that checks the cache first and falls back to the database on a miss.

📦 Installation

dotnet add package OmniDataAccess

What this package provides

  • All SQL providers — PostgreSQL, CockroachDB, MySQL, SQL Server, SQLite
  • All cache providers — Redis, in-memory
  • Message queue & pub/sub — IMessageQueueManager (durable, competing-consumer queue) and IPubSubManager (fire-and-forget broadcast), each with a Redis-backed and in-memory implementation
  • IHybridCacheManager — cache-aside pattern wired to any registered SQL + cache provider
  • DI extension methods for all of the above

DI Registration

// SQL provider
builder.Services.AddPostgresDatabaseManager("Host=localhost;Database=myapp");
// or: AddMySqlDatabaseManager / AddSqlServerDatabaseManager / AddSqliteDatabaseManager

// Cache provider
builder.Services.AddRedisCacheManager(o => o.ConnectionString = "localhost:6379");
// or: AddMemCacheManager()

// Message queue / pub-sub (optional)
builder.Services.AddRedisQueueManager(o => o.ConnectionString = "localhost:6379");
builder.Services.AddRedisPubSubManager(o => o.ConnectionString = "localhost:6379");
// or: AddMemQueueManager() / AddMemPubSubManager()

// Hybrid cache (requires ISqlDatabaseManager + ICacheManager already registered)
builder.Services.AddHybridCacheManager();

// Warmup — pre-seeds the SQL connection pool and establishes the Redis multiplexer
// before the first request is served (fires during app.Run())
builder.Services.AddOmniWarmUp();              // 1 SQL pool connection per manager
builder.Services.AddOmniWarmUp(sqlConnections: 5); // 5 SQL pool connections per manager

Multiple instances of the same provider (keyed DI)

Register more than one manager for the same (or a different) provider with the databaseManagerName / cacheManagerName overload — each is also registered as a .NET 8 keyed service, resolvable with [FromKeyedServices("name")]. See the SqlDatabases README and NoSqlDatabases README for the full examples.


Hybrid Cache — IHybridCacheManager

Cache-aside: reads come from cache; on a miss the database is queried, the result is written to cache, and then returned.

Query-based overloads

// Single object
User? user = await hybrid.GetOrSetAsync<User>(
    key:        $"user:{id}",
    query:      "SELECT * FROM users WHERE id = @id",
    parameters: new { id },
    expiry:     TimeSpan.FromMinutes(15),
    token:      cancellationToken
);

// Collection
IEnumerable<Post> posts = await hybrid.GetOrSetListAsync<Post>(
    key:    "posts:recent",
    query:  "SELECT * FROM posts ORDER BY created_at DESC LIMIT 50",
    expiry: TimeSpan.FromMinutes(5),
    token:  cancellationToken
);

Delegate-based overloads

Use when the fetch is more complex than a single raw query.

// Single object
User? user = await hybrid.GetOrSetAsync<User>(
    key:     $"user:{id}",
    dbFetch: ct => db.FindSingleAsync<User>("SELECT * FROM users WHERE id = @id", new { id }, token: ct),
    expiry:  TimeSpan.FromMinutes(15),
    token:   cancellationToken
);

// Collection — works with any custom fetch function (ORM, multiple joins, etc.)
IEnumerable<Post> posts = await hybrid.GetOrSetListAsync<Post>(
    key:     $"posts:user:{userId}",
    dbFetch: ct => db.FindAsync<Post>(
        "SELECT * FROM posts WHERE user_id = @uid ORDER BY created_at DESC",
        new { uid = userId },
        token: ct),
    expiry: TimeSpan.FromMinutes(10),
    token:  cancellationToken
);

Cache invalidation

await hybrid.InvalidateAsync($"user:{id}");

await hybrid.InvalidateManyAsync(new[]
{
    $"user:{id}",
    "users:all",
    $"posts:user:{id}",
});

Typical service pattern

public class PostService(IHybridCacheManager hybrid, ISqlDatabaseManager db)
{
    private static readonly TimeSpan Ttl = TimeSpan.FromMinutes(10);

    public Task<IEnumerable<Post>> GetAllAsync(CancellationToken ct) =>
        hybrid.GetOrSetListAsync<Post>(
            "posts:all",
            "SELECT * FROM posts ORDER BY created_at DESC",
            expiry: Ttl, token: ct);

    public Task<Post?> GetByIdAsync(Guid id, CancellationToken ct) =>
        hybrid.GetOrSetAsync<Post>(
            $"posts:{id}",
            "SELECT * FROM posts WHERE id = @id",
            new { id },
            expiry: Ttl, token: ct);

    public async Task UpdateAsync(Post post, CancellationToken ct)
    {
        await db.UpdateAsync(post, token: ct);
        await hybrid.InvalidateManyAsync([$"posts:{post.Id}", "posts:all"]);
    }
}

Startup Warmup

The first call to ISqlDatabaseManager pays for TCP connection + TLS handshake + database authentication. RedisCacheManager connects to Redis lazily too. Pre-warming eliminates this cold-start latency before any requests are served.

Hosted service (automatic)

builder.Services.AddPostgresDatabaseManager("...");
builder.Services.AddRedisCacheManager(o => o.ConnectionString = "localhost:6379");
builder.Services.AddOmniWarmUp();               // default: 1 SQL connection per manager
builder.Services.AddOmniWarmUp(sqlConnections: 5); // open 5 pool slots per SQL manager

AddOmniWarmUp registers a hosted service that runs during app.Run() — after builder.Build(), before the first request.

Explicit (after builder.Build())

var app = builder.Build();

await app.Services.GetRequiredService<ISqlDatabaseManager>().WarmUpAsync();
await app.Services.GetRequiredService<ISqlDatabaseManager>().WarmUpAsync(connections: 5);
await app.Services.GetRequiredService<ICacheManager>().WarmUpAsync();

app.Run();

For SQL-only warmup (without OmniDataAccess meta-package) use AddOmniSqlWarmUp() from OmniDataAccess.SqlDatabases.

Multi-tenant / sharded databases

The connection pool is keyed by database name, so warming the default database does not warm any other database on the same server — each distinct database pays its own cold-start cost the first time it's used. Pass the known database names up front to warm them all at startup:

builder.Services.AddOmniWarmUp(sqlConnections: 5, sqlDatabases: ["tenant_gh", "tenant_ng"]);

// or explicit:
await app.Services.GetRequiredService<ISqlDatabaseManager>()
    .WarmUpAsync(connections: 5, databases: ["tenant_gh", "tenant_ng"]);

Quick Start — Raw Manager

// Standalone
var db = new PostgresDatabaseManager(new DatabaseManagerOptions("Host=localhost;Database=myapp"));

// Query
var users = await db.FindAsync<User>("SELECT * FROM users WHERE active = @active", new { active = true });

// Scalar
int count = await db.ExecuteScalarAsync<int>("SELECT COUNT(1) FROM users");

// DML
DatabaseResult r = await db.ExecuteAsync("DELETE FROM sessions WHERE expires_at < @now", new { now = DateTime.UtcNow });

// Pagination
PaginatedResult<IEnumerable<User>> page = await db.FindPagedAsync<User>(
    "SELECT * FROM users ORDER BY created_at DESC", page: 1, limit: 20);

// Streaming
await foreach (var order in db.FindStreamAsync<Order>("SELECT * FROM orders WHERE status = 'pending'"))
    await ProcessAsync(order);

// Transaction
await db.BeginTransactionAsync(async tx =>
{
    await db.InsertAsync(user,  transaction: tx);
    await db.InsertAsync(audit, transaction: tx);
});

SQL failures throw DatabaseManagerException/DatabaseConstraintViolationException with the original exception preserved and structured ErrorCode info attached; cache write failures throw CacheManagerException with a Reason. Stored procedures with OUTPUT parameters are called via ExecuteNonQueryAsync(procedureName, IEnumerable<OmniParameter>, ...). See the OmniDataAccess.Core README and OmniDataAccess.SqlDatabases README for details.


Further Reading

Document Contents
USAGE.md Full API reference with examples for every method
README.md ORM layer (OmniDB, OmniQuery, OmniCache, migrations)
src/OmniDataAccess.SqlDatabases/README.md SQL provider detail
src/OmniDataAccess.NoSqlDatabases/README.md Cache, message queue & pub/sub provider detail
src/OmniDataAccess.Core/README.md Annotations, configuration, result types

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 166 8/2/2026
1.1.0-preview.260731.1 64 7/31/2026
1.1.0-preview.260730.1 103 7/30/2026
1.1.0-preview.260729.1 75 7/29/2026
1.1.0-preview.260719.1 108 7/19/2026
1.1.0-preview.260715.1 70 7/15/2026
1.1.0-preview.260706.2 80 7/6/2026
1.1.0-preview.260706.1 63 7/6/2026
1.1.0-preview.260705.1 66 7/5/2026
1.1.0-preview.260704.2 66 7/4/2026
1.1.0-preview.260704.1 68 7/4/2026
1.1.0-preview.260703.2 65 7/3/2026
1.1.0-preview.260703.1 62 7/3/2026
1.1.0-preview.260621.1 65 6/21/2026
1.1.0-preview.260620.1 77 6/20/2026
1.0.1 173 11/24/2025
1.0.0 241 10/19/2025