Shardis.Query.EntityFrameworkCore
0.2.2
dotnet add package Shardis.Query.EntityFrameworkCore --version 0.2.2
NuGet\Install-Package Shardis.Query.EntityFrameworkCore -Version 0.2.2
<PackageReference Include="Shardis.Query.EntityFrameworkCore" Version="0.2.2" />
<PackageVersion Include="Shardis.Query.EntityFrameworkCore" Version="0.2.2" />
<PackageReference Include="Shardis.Query.EntityFrameworkCore" />
paket add Shardis.Query.EntityFrameworkCore --version 0.2.2
#r "nuget: Shardis.Query.EntityFrameworkCore, 0.2.2"
#:package Shardis.Query.EntityFrameworkCore@0.2.2
#addin nuget:?package=Shardis.Query.EntityFrameworkCore&version=0.2.2
#tool nuget:?package=Shardis.Query.EntityFrameworkCore&version=0.2.2
Shardis.Query.EntityFrameworkCore
Entity Framework Core query executor for Shardis (Where/Select pushdown, unordered streaming, preview ordered buffering, optional failure strategy decoration).
Install
dotnet add package Shardis.Query.EntityFrameworkCore --version 0.1.*
When to use
- Your shard-local persistence is EF Core and you want query pushdown and streaming.
- You need a tested executor that integrates with
DbContext
per shard.
What’s included
EntityFrameworkCoreShardQueryExecutor
— concrete executor translating queries into EF Core operations.EfCoreShardQueryExecutor.CreateUnordered
andCreateOrdered
(buffered ordered variant; materializes then orders).EfCoreExecutionOptions
(channel capacity, per-shard command timeout, shard concurrency, context lifetime control).EntityFrameworkCoreShardFactory<TContext>
/PooledEntityFrameworkCoreShardFactory<TContext>
for per-shard context creation.- Wiring examples for registering
DbContext
instances per shard.
Quick start
// Build a shard factory (pure creation only)
var dbFactory = new EntityFrameworkCoreShardFactory<MyDbContext>(sid =>
new DbContextOptionsBuilder<MyDbContext>()
.UseSqlite($"Data Source=shard-{sid.Value}.db")
.Options);
// (Optional) seed outside the factory
foreach (var sid in new[]{ new ShardId("0"), new ShardId("1") })
{
await using var ctx = await dbFactory.CreateAsync(sid);
// seed if empty
}
// Adapter to non-generic DbContext for executor
IShardFactory<DbContext> adapter = new DelegatingShardFactory<DbContext>((sid, ct) => new ValueTask<DbContext>(dbFactory.Create(sid)));
var exec = new EntityFrameworkCoreShardQueryExecutor(
shardCount: 2,
contextFactory: adapter,
merge: (streams, ct) => UnorderedMerge.Merge(streams, ct));
var query = ShardQuery.For<Person>(exec)
.Where(p => p.Age >= 30)
.Select(p => p.Name);
var names = await query.ToListAsync();
Integration notes
- Works with
Shardis.Query
core abstractions; register per-shardDbContext
factories in DI. - Recommended DI approach using
Shardis.DependencyInjection
:
var services = new ServiceCollection()
.AddShards<MyDbContext>(2, shard => new MyDbContext(BuildOptionsFor(shard)))
.AddShardisEfCoreUnordered<MyDbContext>(
shardCount: 2,
contextFactory: new EntityFrameworkCoreShardFactory<MyDbContext>(BuildOptionsFor))
.DecorateShardQueryFailureStrategy(BestEffortFailureStrategy.Instance) // optional
.AddShardisQueryClient();
await using var provider = services.BuildServiceProvider();
var client = provider.GetRequiredService<IShardQueryClient>();
var active = await client.Query<Person>().Where(p => p.IsActive).CountAsync();
Samples & tests
- Samples: samples
Configuration / Options
- ChannelCapacity (
EfCoreExecutionOptions.ChannelCapacity
): bounded backpressure for unordered merge (null = unbounded internal channel). - PerShardCommandTimeout: database command timeout per shard query (best‑effort; ignored if provider disallows).
- Concurrency: maximum shard fan‑out (limits simultaneous DbContext queries). Null = unbounded.
- DisposeContextPerQuery: if false, retains one
DbContext
per shard for executor lifetime (reduces allocations; ensure thread-safety per context usage pattern). - Ordered factory:
AddShardisEfCoreOrdered
/EfCoreShardQueryExecutor.CreateOrdered
buffers all shard results before ordering; use only for bounded result sets. - Failure strategy decoration: call
DecorateShardQueryFailureStrategy(BestEffortFailureStrategy.Instance)
(or custom) after registering an executor.
Cancellation & Timeouts
All query methods accept a CancellationToken
(propagated to EF Core async providers). If PerShardCommandTimeout
is set, it is applied per shard query and restored for retained contexts.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var exec = EfCoreShardQueryExecutor.CreateUnordered(
shardCount,
contextFactory,
new EfCoreExecutionOptions { PerShardCommandTimeout = TimeSpan.FromSeconds(3) });
var names = await exec.Query<Person>().Select(p => p.Name).ToListAsync(cts.Token);
Backpressure
ChannelCapacity
bounds the number of buffered items produced ahead of the consumer in unordered merges. Tune for throughput vs memory (typical range: 4–256). null
= unbounded (fastest, more memory risk under very large fan-out).
Failure Behavior
Default: fail-fast — the first shard exception terminates the merged enumeration. To aggregate errors and continue best-effort across shards:
services.DecorateShardQueryFailureStrategy(BestEffortFailureStrategy.Instance);
Metrics & Tracing
The executor emits Activity
instances via source name Shardis.Query
with tags:
query.source
,query.result
,query.where.count
,query.has.select
,shard.count
,query.duration.ms
, and per-shardshard.index
& optionaldb.command_timeout.seconds
. Integrate with OpenTelemetry by adding anActivityListener
or OTEL SDK.
Capabilities & limits
- ✅ Pushes where/select operations to EF Core where supported.
- ⚠️ Ordered (buffered) factory materializes all results. Avoid for unbounded / very large sets.
- ⚠️ Ordered streaming improvements (k-way merge) planned; present variant trades memory for simplicity.
- 🧩 Requires EF Core provider matching your database version.
Versioning & compatibility
- SemVer; see CHANGELOG: CHANGELOG
Contributing
- PRs welcome. See CONTRIBUTING
License
- MIT — see LICENSE
Links
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 is compatible. 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
- Microsoft.EntityFrameworkCore (>= 8.0.8)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.8)
- Shardis.Query (>= 0.2.2)
-
net9.0
- Microsoft.EntityFrameworkCore (>= 8.0.8)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.8)
- Shardis.Query (>= 0.2.2)
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 |
---|---|---|
0.2.2 | 26 | 9/11/2025 |
0.2.2-prerelease0001 | 29 | 9/11/2025 |
0.2.1 | 39 | 9/10/2025 |
0.2.1-prerelease0001 | 37 | 9/9/2025 |
0.2.0 | 46 | 9/8/2025 |
0.1.0-prerelease0086 | 57 | 9/7/2025 |
0.1.0-prerelease0085 | 60 | 9/7/2025 |
Initial release. Full notes: https://github.com/veggerby/shardis/blob/main/CHANGELOG.md#010---2025-08-25