RepoStack 0.0.1-alpha-1
dotnet add package RepoStack --version 0.0.1-alpha-1
NuGet\Install-Package RepoStack -Version 0.0.1-alpha-1
<PackageReference Include="RepoStack" Version="0.0.1-alpha-1" />
<PackageVersion Include="RepoStack" Version="0.0.1-alpha-1" />
<PackageReference Include="RepoStack" />
paket add RepoStack --version 0.0.1-alpha-1
#r "nuget: RepoStack, 0.0.1-alpha-1"
#:package RepoStack@0.0.1-alpha-1
#addin nuget:?package=RepoStack&version=0.0.1-alpha-1&prerelease
#tool nuget:?package=RepoStack&version=0.0.1-alpha-1&prerelease
RepoStack
Reusable repository and query abstractions for .NET applications.
RepoStack keeps application code independent from a concrete data-access implementation. The core package contains provider, repository, query, ordering, and transaction contracts. Database-specific integrations live in separate packages; Entity Framework Core is currently provided by RepoStack.EntityFrameworkCore.
Contents
- Features
- Installation
- Queries and projections
- Write operations
- Transactions
- Quick start with Entity Framework Core
- PureSpec integration
- License
Features
- Generic read providers through
IProvider<TEntity> - Generic repositories through
IRepository<TEntity> - Filtered, ordered, and paged queries with
Query<TEntity> - Server-side projections with
Query<TEntity, TResult> ToArrayAsync,FirstOrDefaultAsync,SingleOrDefaultAsync,SingleAsync,CountAsync, andAnyAsync- Expression-based provider overloads without constructing
Query<TEntity> - Single-item and batch add, update, and delete operations
- Optional automatic transaction start for repository mutations
- Cancellation support on asynchronous database operations
- No-tracking reads by default in the EF Core provider
Installation
Install the core abstractions package:
dotnet add package RepoStack --version 0.0.1-alpha-1
Install the Entity Framework Core integration when using EF Core:
dotnet add package RepoStack.EntityFrameworkCore --version 0.0.1-alpha-1
Install the PureSpec integration when the application uses PureSpec specifications:
dotnet add package RepoStack.PureSpecExtension --version 0.0.1-alpha-1
Queries and projections
Query<TEntity> describes an entity query. Its optional predicate, orderings, offset, and limit are applied in that order. Query<TEntity, TResult> adds a LINQ expression for server-side projection:
var query = new Query<Book, BookListItem>(
predicate: book => book.Genre == Genre.Fiction,
selector: book => new BookListItem(book.Id, book.Title),
orderings: [
new QueryOrder<Book, string>(book => book.Title),
new QueryOrder<Book, int>(book => book.Id)
],
offset: 20,
limit: 20);
BookListItem[] page = await books.ToArrayAsync(query, cancellationToken);
Use descending: true for descending order. Multiple QueryOrder instances become a primary ordering followed by ThenBy / ThenByDescending orderings.
For common entity queries, IProvider<TEntity> also provides overloads that accept the predicate, an array of orderings, limit, and offset directly. This avoids creating a Query<TEntity>:
Book[] page = await books.ToArrayAsync(
book => book.Genre == Genre.Fiction,
[new QueryOrder<Book, string>(book => book.Title)],
limit: 20,
offset: 0,
cancellationToken);
FirstOrDefaultAsync and SingleOrDefaultAsync accept the same parameters and also have expression-only overloads. SingleAsync, CountAsync, and AnyAsync provide expression-only overloads as well:
Book? book = await books.SingleOrDefaultAsync(
book => book.Isbn == isbn, [], null, null, cancellationToken);
long count = await books.CountAsync(book => book.IsAvailable, cancellationToken);
bool exists = await books.AnyAsync(book => book.Isbn == isbn, cancellationToken);
Write operations
Use IRepository<TEntity> when the service needs mutations as well as reads:
public sealed class BookService(IRepository<Book> books)
{
public async ValueTask AddAsync(Book book, CancellationToken cancellationToken)
{
await books.AddAsync(book, cancellationToken);
}
public async ValueTask DeleteArchivedAsync(CancellationToken cancellationToken)
{
await books.DeleteManyAsync(
new Query<Book>(book => book.IsArchived),
cancellationToken);
}
}
AddAsync, AddManyAsync, UpdateAsync, UpdateManyAsync, and DeleteAsync save changes through the current DbContext. DeleteManyAsync uses EF Core's set-based ExecuteDeleteAsync and returns the number of deleted rows.
Transactions
By default, repository mutations use the current EF Core transaction when one exists. To automatically start a transaction before a mutation, enable the option during registration:
services.AddRepoStackEntityFrameworkCore(
startTransactionsBeforeAnyModification: true);
When this option is enabled, commit or roll back through the injected ITransactionManager:
public sealed class ImportService(
IRepository<Book> books,
ITransactionManager transactions)
{
public async ValueTask ImportAsync(
Book[] importedBooks,
CancellationToken cancellationToken)
{
await books.AddManyAsync(importedBooks, cancellationToken);
await transactions.CommitTransactionIfExistsAsync(cancellationToken);
}
}
The manager also exposes BeginTransactionIfNotExistsAsync and RollbackTransactionIsExistsAsync for explicit transaction control. The transaction is tied to the registered DbContext scope.
Quick start with Entity Framework Core
Register the application's DbContext and RepoStack in the service collection:
using Microsoft.EntityFrameworkCore;
using RepoStack.EntityFrameworkCore;
services
.AddDbContext<DbContext, BooksDbContext>(options =>
options.UseSqlServer(connectionString))
.AddRepoStackEntityFrameworkCore();
AddRepoStackEntityFrameworkCore() registers:
| Abstraction | Default implementation | Lifetime |
|---|---|---|
IProvider<TEntity> |
BaseProvider<TEntity> |
Transient |
IRepository<TEntity> |
BaseRepository<TEntity> |
Transient |
ITransactionManager |
TransactionManager |
Scoped |
Inject the abstraction you need into an application service or handler:
using RepoStack;
public sealed class BookService(IProvider<Book> books)
{
public ValueTask<Book[]> GetAvailableBooksAsync(CancellationToken cancellationToken) =>
books.ToArrayAsync(
new Query<Book>(
predicate: book => book.IsAvailable,
orderings: [new QueryOrder<Book, string>(book => book.Title)],
limit: 20),
cancellationToken);
}
PureSpec integration
RepoStack.PureSpecExtension bridges PureSpec specifications and RepoStack queries. It adds ToQuery(...) extension methods for both ISpecification<TEntity> and IProjectedSpecification<TEntity, TResult>.
The extensions preserve the specification predicate and, for projected specifications, the selector. They can also add:
- no ordering or a custom
IQueryOrder<TEntity>sequence; - ascending or descending ordering from a key selector;
- optional
limitandoffsetpaging.
using PureSpec;
using RepoStack;
using RepoStack.PureSpecExtension;
public sealed class BookService(IProvider<Book> books)
{
public ValueTask<Book[]> FindAsync(
ISpecification<Book> specification,
CancellationToken cancellationToken) =>
books.ToArrayAsync(
specification.ToQuery(
ordering: book => book.Title,
limit: 20,
offset: 0),
cancellationToken);
}
For a projected PureSpec specification, the same API returns IQuery<TEntity, TResult> and keeps the projection server-side:
IProjectedSpecification<Book, BookListItem> specification = GetBookListSpecification();
BookListItem[] result = await books.ToArrayAsync(
specification.ToQuery(book => book.Title, descending: false, limit: 20),
cancellationToken);
Use the overload accepting IEnumerable<IQueryOrder<TEntity>> when multiple ordering criteria are needed. RepoStack.PureSpecExtension does not provide a database provider; it only adapts PureSpec specifications for use with RepoStack providers and repositories.
License
| 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
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on RepoStack:
| Package | Downloads |
|---|---|
|
RepoStack.EntityFrameworkCore
Package Description |
|
|
RepoStack.PureSpecExtension
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1-alpha-1 | 76 | 9/3/2026 |
| 0.0.1-alpha | 79 | 8/30/2026 |
Add expression-based IProvider overloads for common entity queries.