Trellis.EntityFrameworkCore
3.0.0-alpha.505
See the version list below for details.
dotnet add package Trellis.EntityFrameworkCore --version 3.0.0-alpha.505
NuGet\Install-Package Trellis.EntityFrameworkCore -Version 3.0.0-alpha.505
<PackageReference Include="Trellis.EntityFrameworkCore" Version="3.0.0-alpha.505" />
<PackageVersion Include="Trellis.EntityFrameworkCore" Version="3.0.0-alpha.505" />
<PackageReference Include="Trellis.EntityFrameworkCore" />
paket add Trellis.EntityFrameworkCore --version 3.0.0-alpha.505
#r "nuget: Trellis.EntityFrameworkCore, 3.0.0-alpha.505"
#:package Trellis.EntityFrameworkCore@3.0.0-alpha.505
#addin nuget:?package=Trellis.EntityFrameworkCore&version=3.0.0-alpha.505&prerelease
#tool nuget:?package=Trellis.EntityFrameworkCore&version=3.0.0-alpha.505&prerelease
Trellis.EntityFrameworkCore
EF Core conventions and helpers for Trellis value objects, Maybe<T>, and Result-based persistence.
Installation
dotnet add package Trellis.EntityFrameworkCore
Quick Example
using Microsoft.EntityFrameworkCore;
using Trellis;
using Trellis.EntityFrameworkCore;
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) =>
configurationBuilder.ApplyTrellisConventions(typeof(AppDbContext).Assembly);
// Reflection-free alternative — generated at compile time, no assembly scan:
// configurationBuilder.ApplyTrellisConventionsFor<AppDbContext>();
Maybe<Customer> customer = await dbContext.Customers.FirstOrDefaultMaybeAsync(cancellationToken);
Result<int> saved = await dbContext.SaveChangesResultAsync(cancellationToken);
Key Features
- Commit ownership:
EfUnitOfWork.BeginScope()returnsIUnitOfWorkScope;IsOwneris true only for the outer scope. Nested commands defer persistence and event dispatch until the owning command succeeds; DTO/Unit outer responses retain nested aggregate events. Automatic event dispatch under a manually owned outer scope is rejected; use explicit post-commit dispatch instead. - Apply Trellis value converters and owned-type conventions with one registration point.
- Owned-collection (
OwnsMany) children that declare their own primary key are treated as domain-assigned: the key is markedValueGenerated.Never, so an application-suppliedGuid/long/intkey persists on every provider (no SQL Server IDENTITY544error, no spurious 409 when adding a child to an already-loaded parent). Opt back into store generation with an explicitValueGeneratedOnAdd()or[DatabaseGenerated(DatabaseGeneratedOption.Identity)]. - Query
Maybe<T>naturally instead of dropping to storage-specific null handling. - Return
Result<int>orResultfrom save operations instead of throwing on expected failures. - Idempotent inserts on a unique constraint via
db.TryInsertUniqueAsync(entity, ct)— duplicate-key violations surface as a failedResult<TEntity>carrying anError.Conflictwith reason code"duplicate.key"and the provider-extractedConstraintName/ConstraintTableNametelemetry fields, so worker outboxes and "save unless exists" deduplication never throw on redelivery. - Typed cursor pagination via
IQueryable<T>.ToPageAsync(request, seek, …)—SeekDefinitionkeeps single/composite, ascending/descending ordering and seek predicates together; malformed client state returnsError.InvalidInput. RepositoryBase<TAggregate, TId>— staging-only base class (Add/Remove/Query/Exists/Count).IUnitOfWork/EfUnitOfWork<TContext>— single commit boundary for staged changes.TransactionalCommandBehavior— Mediator pipeline behavior that auto-commits after successful command handlers (requires Mediator pipeline registration). Also commits onResult.FailAfterCommit<T>(error)outcomes so persist-on-failure handlers (e.g., a worker recording a permanent-failure transition) can stage state alongside the failed result.
Typed predicates over optional values
var overdue = await dbContext.Orders
.WhereHasValue(o => o.SubmittedAt, value => value < cutoff)
.ToListAsync(cancellationToken);
Breaking change: WhereLessThan, WhereLessThanOrEqual, WhereGreaterThan,
and WhereGreaterThanOrEqual are replaced by WhereHasValue(selector, predicate).
Move <, <=, >, or >= into the value lambda. The overload accepts an
Expression<Func<TInner, bool>>, including reusable expression variables, not a
compiled delegate. Absent values are always excluded, even for a constant-true predicate.
Presence-only WhereHasValue(selector), equality, and ordering helpers are unchanged.
C# checks the predicate's operators; the configured provider must translate them.
String/GUID ordering follows provider semantics, and unsupported translations
(such as DateTimeOffset relational comparisons on SQLite) throw without a
client-side fallback. The helper targets storage directly; scalar value-object
.Value access still requires AddTrellisInterceptors().
For shared domain specifications, continue using Maybe<T>.HasValueWhere with
an inline lambda and AddTrellisInterceptors() for EF execution.
Typed seek pagination
var seek = SeekDefinition.Descending<Order, DateTimeOffset>(o => o.CreatedAt)
.ThenAscending(o => o.Id.Value);
Result<Page<Order>> page = await PageRequest.TryCreate(cursor, limit)
.BindAsync(request => authorizedOrders.AsNoTracking()
.ToPageAsync(request, seek, cancellationToken: ct));
Supply an authorized, pre-filtered IQueryable<Order>. PageRequest distinguishes
missing input from invalid empty cursors/non-positive limits; above-cap limits
clamp by default (PageSizeLimitPolicy.Reject opts into rejection). The helper
decodes typed state, seeks before Take(Applied + 1), and assembles a forward page.
Boundary values are projected with the database query using the same key
expressions, not recomputed in C# after materialization. Provider-translated
functions are supported when the provider translates the complete query.
End with a stable unique key. Null keys are unsupported; verify your provider's
translation and comparison/collation semantics. .Id.Value projection requires
AddTrellisInterceptors(). There is no client-side fallback or snapshot guarantee,
and descending traversal is not previous-page support. Cancellation and provider
failures propagate rather than becoming malformed-cursor errors.
Use explicit key codecs or seek.WithCodec(...) for custom/context-bound/protected
state. Built-ins are versioned and unsigned; old unversioned tokens are rejected.
The single-key ascending ToPageAsync(pageSize, cursor, keySelector, …) convenience
remains. For non-translatable computed ordering, use an explicitly bounded
application algorithm with Core codecs and PageBuilder instead.
Documentation
Part of Trellis
This package is part of the Trellis framework.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Mediator.Abstractions (>= 3.0.2)
- Microsoft.EntityFrameworkCore (>= 10.0.12)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- OpenTelemetry.Api (>= 1.18.0)
- Trellis.Authorization (>= 3.0.0-alpha.505)
- Trellis.Core (>= 3.0.0-alpha.505)
- Trellis.Mediator (>= 3.0.0-alpha.505)
- Trellis.Persistence.Abstractions (>= 3.0.0-alpha.505)
- Trellis.Primitives (>= 3.0.0-alpha.505)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Trellis.EntityFrameworkCore:
| Package | Downloads |
|---|---|
|
Trellis.ServiceDefaults
Opinionated service composition defaults for Trellis web services. Provides a tiered builder that wires ASP integration, Mediator behaviors, FluentValidation, resource authorization, actor providers, and EF Core Unit of Work in canonical order. |
|
|
Trellis.EntityFrameworkCore.Outbox
Transactional outbox for Trellis. Atomically captures aggregate domain events to an EF Core table in the same transaction as the aggregate change, then relays them to Trellis domain-event handlers — durable, at-least-once, in-process dispatch. |
|
|
Trellis.EntityFrameworkCore.Inbox
Transactional inbox for Trellis — the consume-side complement to the outbox. Makes integration-event consumption idempotent: redeliveries of the same message are deduplicated by message id within the consumer's unit of work, so a handler's side effects commit exactly once. EF Core reference store. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-alpha.527 | 0 | 10/1/2026 |
| 3.0.0-alpha.526 | 30 | 9/30/2026 |
| 3.0.0-alpha.524 | 62 | 9/27/2026 |
| 3.0.0-alpha.520 | 78 | 9/25/2026 |
| 3.0.0-alpha.516 | 171 | 9/22/2026 |
| 3.0.0-alpha.513 | 74 | 9/22/2026 |
| 3.0.0-alpha.505 | 197 | 9/13/2026 |
| 3.0.0-alpha.495 | 245 | 8/24/2026 |
| 3.0.0-alpha.458 | 195 | 8/19/2026 |
| 3.0.0-alpha.455 | 140 | 8/19/2026 |
| 3.0.0-alpha.449 | 91 | 8/18/2026 |
| 3.0.0-alpha.447 | 86 | 8/18/2026 |
| 3.0.0-alpha.432 | 126 | 7/6/2026 |
| 3.0.0-alpha.428 | 137 | 7/3/2026 |
| 3.0.0-alpha.425 | 156 | 6/27/2026 |
| 3.0.0-alpha.419 | 103 | 6/24/2026 |
| 3.0.0-alpha.418 | 188 | 6/23/2026 |
| 3.0.0-alpha.417 | 88 | 6/23/2026 |
| 3.0.0-alpha.397 | 92 | 6/18/2026 |
| 3.0.0-alpha.396 | 92 | 6/18/2026 |