OmniDataAccess 1.1.0
dotnet add package OmniDataAccess --version 1.1.0
NuGet\Install-Package OmniDataAccess -Version 1.1.0
<PackageReference Include="OmniDataAccess" Version="1.1.0" />
<PackageVersion Include="OmniDataAccess" Version="1.1.0" />
<PackageReference Include="OmniDataAccess" />
paket add OmniDataAccess --version 1.1.0
#r "nuget: OmniDataAccess, 1.1.0"
#:package OmniDataAccess@1.1.0
#addin nuget:?package=OmniDataAccess&version=1.1.0
#tool nuget:?package=OmniDataAccess&version=1.1.0
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) andIPubSubManager(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 | Versions 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. |
-
net8.0
- OmniDataAccess.Core (>= 1.2.0)
- OmniDataAccess.NoSqlDatabases (>= 1.2.0)
- OmniDataAccess.SqlDatabases (>= 2.0.0)
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 |