Carneiro.Core.Repository 7.6.2

dotnet add package Carneiro.Core.Repository --version 7.6.2
                    
NuGet\Install-Package Carneiro.Core.Repository -Version 7.6.2
                    
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="Carneiro.Core.Repository" Version="7.6.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Carneiro.Core.Repository" Version="7.6.2" />
                    
Directory.Packages.props
<PackageReference Include="Carneiro.Core.Repository" />
                    
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 Carneiro.Core.Repository --version 7.6.2
                    
#r "nuget: Carneiro.Core.Repository, 7.6.2"
                    
#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 Carneiro.Core.Repository@7.6.2
                    
#: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=Carneiro.Core.Repository&version=7.6.2
                    
Install as a Cake Addin
#tool nuget:?package=Carneiro.Core.Repository&version=7.6.2
                    
Install as a Cake Tool

Carneiro.Core.Repository

The EF Core data-access layer for the whole library: a SQL Server–backed IUnitOfWork<TDbContext> that every CRUD, query, count, sum, soft-delete, transaction and stored-procedure operation flows through, plus the DatabaseBuilder/IServiceCollection extensions used to register it. Entities are generic over Carneiro.Core.Entities' IAuditableEntity/IEntity/IEntityDistributed — IDs are either int (IEntity) or Guid (IEntityDistributed).

Registration

services.AddDatabase<AppDbContext>(configuration)   // "DatabaseContext" connection string + "Database" config section
    .AddUnitOfWork<AppDbContext>()
    .AddDataProtection<AppDbContext>();              // optional: persist ASP.NET Data Protection keys in the same database

AddDatabase<TDbContext> registers TDbContext with EF Core (AddDbContext, or AddDbContextPool when DatabaseOptions.UseDbContextPool is true) pre-wired for SQL Server only (UseSqlServerWithOptions), and returns an IDatabaseBuilder for chaining. Overloads accept, in various combinations: a raw connection string, a DatabaseOptions instance (object, Action<DatabaseOptions>, or IConfigurationSection), or a full IConfiguration (expects a DatabaseContext connection-string entry and a Database section bindable to DatabaseOptions) — every overload also accepts an extra Action<DbContextOptionsBuilder> for low-level EF configuration on top of what Carneiro.Core.Repository sets up.

IDatabaseBuilder.AddUnitOfWork<T>() registers, all Scoped, for the given DbContext:

  • IUnitOfWork<T> → UnitOfWork<T>
  • IStoredProcedureUnitOfWork<T> → StoredProcedureUnitOfWork<T>
  • ITransactionalUnitOfWork<T> → TransactionalUnitOfWork<T>

AddUnitOfWork<TService, TImplementation, TDbContext>() registers a custom IUnitOfWork<TDbContext> implementation/subclass instead (still wiring up the transactional/stored-procedure companions). AddDataProtection<T>() (with optional appName and/or keyLifeTime) calls ASP.NET Core's AddDataProtection().PersistKeysToDbContext<T>(), where T must implement IDataProtectionKeyContext.

IUnitOfWork<TDbContext>

The central interface consumers inject. Generic over TDbContext : DbContext; implements IDisposable/IAsyncDisposable and disposes the underlying DbContext on Dispose/DisposeAsync.

  • CanConnectAsync() — wraps DbContext.Database.CanConnectAsync().
  • Create — Add<T>, AddRange<T>, AddAsync<T> (sync/async, with/without CancellationToken), constrained to T : class, IAuditableEntity. Before staging the entity, these stamp IsActive = true, IsDeleted = false, CreateDate = DateTime.UtcNow, UpdateDate = null, DeleteDate = null — audit fields are always set by the unit of work, never left to the caller.
  • Update — Update<T>, UpdateRange<T> stamp UpdateDate = DateTime.UtcNow then call DbContext.Update/UpdateRange.
  • Delete (soft by default) — Delete<T>(entity) / Delete<T>(entities) soft-delete: stamp IsActive = false, IsDeleted = true, DeleteDate = DateTime.UtcNow, then Update/UpdateRange the row(s). The Delete<T>(entity, hardDelete: true) / Delete<T>(entities, hardDelete: true) overloads instead call DbContext.Set<T>().Remove/RemoveRange, bypassing the audit stamp entirely.
  • Querying — Query<T>() and Query<T>(expression) return IQueryable<T> filtered to IsDeleted == false; Query<T>(int id) / Query<T>(int id, expression) add an Id == id predicate on top and additionally require T : IEntity (so these int id overloads only work for int-keyed entities — for IEntityDistributed/Guid-keyed entities use the expression-based overloads instead, e.g. FirstOrDefaultAsync<T>(x => x.Id == guidId)). Soft-delete filtering here is applied in these LINQ helpers, not as an EF Core model-level global query filter — going around the unit of work straight to DbContext.Set<T>() (as the hard-delete path does) bypasses it.
  • Read helpers — GetAsync<T> (returns List<T>), AnyAsync<T>, FirstAsync<T>, FirstOrDefaultAsync<T>, SingleAsync<T>, SingleOrDefaultAsync<T>, LastAsync<T>, LastOrDefaultAsync<T>. Each has overloads for no predicate, an int id, an Expression<Func<T, bool>>, an id + expression combo, and a trailing CancellationToken — all routed through Query<T>(...) (so all respect the IsDeleted == false filter), except the three ...OrDefaultAsync<T>(int id) shortcuts which query DbContext.Set<T>() directly with an equivalent Id == id && IsDeleted == false predicate.
  • Aggregates — CountAsync<T>() / CountAsync<T>(expression), and SumAsync<T> overloads for decimal, decimal?, int, int? projections — all built on Query<T>().
  • SaveAsync() / SaveAsync(CancellationToken) — DbContext.SaveChangesAsync(...); nothing above is persisted until this is called.

IBaseRepository / BaseRepository<TDbContext, T>

An optional thin, auto-saving wrapper over IUnitOfWork<TDbContext> for building a typed repository per entity, instead of injecting IUnitOfWork<TDbContext> directly everywhere:

  • IBaseRepository is a non-generic IDisposable marker; BaseRepository<TDbContext> implements the standard dispose pattern by disposing the wrapped UnitOfWork (protected property).

  • IBaseRepository<T> / BaseRepository<TDbContext, T> (T : class, IEntity — int-keyed entities only) add:

    • GetEntityAsync(int id) → UnitOfWork.SingleOrDefaultAsync<T>(t => t.Id == id)
    • UpdateAsync(T entity) / UpdateAsync(List<T> entities) → Update/UpdateRange then SaveAsync()
    • AddAsync(T entity) → AddAsync then SaveAsync()
    • DeleteAsync(T entity) → Delete (soft delete) then SaveAsync()

    Each method commits immediately (calls SaveAsync() itself); there's no batching multiple BaseRepository calls into one SaveAsync. Because it's hard-typed to IEntity, Guid-keyed (IEntityDistributed) entities aren't a fit for BaseRepository<TDbContext, T> — use IUnitOfWork<TDbContext> directly for those.

ITransactionalUnitOfWork<TDbContext>

For explicit multi-step transactions with EF Core's retry-aware execution strategy, registered automatically alongside IUnitOfWork by AddUnitOfWork. Every call ultimately:

  1. Creates an IExecutionStrategy from DbContext.Database.CreateExecutionStrategy().
  2. Opens a new IServiceScope and resolves a new TDbContext from it (not the caller's ambient context).
  3. Begins an IDbContextTransaction at the given IsolationLevel (default ReadCommitted on every overload that doesn't take one explicitly).
  4. Invokes your delegate, then db.SaveChangesAsync() and transaction.CommitAsync().
  5. On exception: logs it, transaction.RollbackAsync(), and rethrows.

Two invocation shapes are supported, each with ExecuteAsync/ExecuteWithResultAsync (result-returning) variants and isolation-level/cancellation-token overload combinations:

  • Fixed shapes — Func<IUnitOfWork<TDbContext>, Task/Task<T>> or Func<IServiceProvider, Task/Task<T>>.
  • ExecuteWithAsync<T> / ExecuteWithResultAsync<T> / ExecuteWithResultAsync<T, Y> — resolves an arbitrary T from the new scope (e.g. a custom repository, or IUnitOfWork<TDbContext> itself), so the callback can invoke methods on any service registered in DI.

Because the delegate operates on a freshly scoped TDbContext/IUnitOfWork<TDbContext>, changes made through the caller's own request-scoped unit of work are unaffected by (and not part of) this transaction — only what the callback does with the injected instance is committed or rolled back.

IStoredProcedureUnitOfWork<TDbContext>

For raw stored-procedure calls that don't map to LINQ, registered automatically alongside IUnitOfWork by AddUnitOfWork.

  • ExecuteStoredProcedureAsync<T>(sql, ..., Func<DbDataReader, Task<T>> action) overloads accept an optional Dictionary<string, object> of named parameters (built into generic DbParameters — name/value only, no direction or explicit DbType), an optional CommandBehavior (default CommandBehavior.Default), and an optional CancellationToken. They open the DbContext's underlying connection, build a CommandType.StoredProcedure command, execute it, hand the DbDataReader to your projection callback, and close the connection in a finally block. These overloads do not wrap the call in an explicit transaction. Every call logs the SQL text and parameter names/values via ILogger before executing — be mindful of sensitive parameter values ending up in logs.
  • ExecuteStoredProcedureAsync<S, T>(sql, IEnumerable<S> sqlParameters, CommandBehavior, Func<DbDataReader, Task<T>>, CancellationToken) (S : DbParameter) is the richer overload: it accepts fully-formed ADO.NET parameters (e.g. SqlParameter with Direction = Output), runs the whole call inside its own ReadCommitted DbTransaction (commit on success, rollback + rethrow on failure), and returns a StoreProcedureResult<T> combining the projected Result with an Output dictionary of any Output/InputOutput parameters.

PaginatedList<T>

A List<T> subclass returned by PaginatedList<T>.CreateAsync(IQueryable<T> source, int pageIndex, int pageSize) (or the page-1 shortcut CreateAsync(source, pageSize)), which runs source.CountAsync() then Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(). Pairs naturally with IUnitOfWork.Query<T>(...), since that already excludes soft-deleted rows. Exposes:

  • PageIndex, PageSize, Total (item count), TotalPages (Ceiling(Total / PageSize))
  • NextPage / PreviousPage (PageIndex ± 1, not clamped to a valid range)
  • HasPreviousPage (PageIndex > 1), HasNextPage (PageIndex < TotalPages)

StoreProcedureResult<T>

Simple result DTO returned only by the DbParameter-collection stored-procedure overload above: Result (the projected T) and Output (Dictionary<string, object> of output parameter values). Overrides ToString() to dump the output dictionary for logging/debugging.

Entity type configurations

  • EntityTypeConfiguration<T> (T : class, IEntity) and DistributedEntityTypeConfiguration<T> (T : class, IEntityDistributed) are abstract IEntityTypeConfiguration<T> base classes that call builder.HasKey(t => t.Id) for you (int vs Guid key respectively) and then delegate the rest of the mapping to an abstract ConfigureEntity(EntityTypeBuilder<T> builder) you implement — use these instead of implementing IEntityTypeConfiguration<T> directly so every entity's primary key is configured consistently. Neither applies an EF Core global query filter for soft delete; that filtering happens at query time in IUnitOfWork, as noted above.
  • DataProtectionKeyConfiguration configures ASP.NET Core Data Protection's DataProtectionKey entity: HasKey(t => t.Id) and ToTable("DataProtectionKey"), with an optional Action<EntityTypeBuilder<DataProtectionKey>> constructor hook for further customization. Used together with IDatabaseBuilder.AddDataProtection<T>().

Other extensions

  • ModelBuilderExtensions.UseUtcDateTimeRead(modelBuilder) — call from OnModelCreating to walk every entity property of CLR type DateTime/DateTime? and install a ValueConverter that stamps DateTimeKind.Utc on read (a no-op on write). SQL Server has no time-zone-aware datetime type, so this keeps values read back from the database consistent with the DateTime.UtcNow audit stamps UnitOfWork writes on create/update/delete.

DatabaseOptions / DatabaseFailureOptions

Bindable from configuration (e.g. the Database section via the AddDatabase(IConfiguration) overload) or built programmatically; consumed by DbContextOptionsBuilderExtensions.UseSqlServerWithOptions, the single place the SQL Server provider is configured (this package does not abstract over other providers):

  • Timeout (default 60 seconds) → CommandTimeout.
  • Failure (DatabaseFailureOptions) → EnableRetryOnFailure(maxRetryCount: Retries, maxRetryDelay: TimeSpan.FromSeconds(Seconds)). DatabaseFailureOptions.Retries defaults to 3, Seconds defaults to 15.
  • EnableSensitiveDataLogging / EnableDetailedErrors (both default false) → the matching EF Core DbContextOptionsBuilder calls.
  • QuerySplittingBehavior (nullable) → UseQuerySplittingBehavior, only applied if set.
  • UseRelationalNulls (nullable) → UseRelationalNulls, only applied if set.
  • MinBatchSize / MaxBatchSize (nullable) → the matching SQL Server provider batching options, only applied if set.
  • UseDbContextPool (default false) → controls whether AddDatabase<T> calls AddDbContextPool<T> instead of AddDbContext<T>.

Both classes override ToString() for easy logging of the effective configuration.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Carneiro.Core.Repository:

Package Downloads
Carneiro.Core.Tests

Test framework

Carneiro.Core.Tests.Abstractions

Test abstractions framework

Carneiro.Core.Cache

Simple cache implementation

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
7.6.2 111 9/28/2026
7.6.1 105 9/28/2026
7.6.0 122 9/16/2026
7.5.12 119 9/16/2026
7.5.11 123 9/15/2026
7.5.10 111 9/15/2026
7.5.9 114 9/14/2026
7.5.8 119 9/10/2026
7.5.7 137 9/6/2026
7.5.7-beta.130 81 9/6/2026
7.5.6 123 9/6/2026
7.5.5 129 8/30/2026
7.5.4 144 8/16/2026
7.5.3 131 8/16/2026
7.5.3-beta.120 81 8/13/2026
7.5.2 136 8/12/2026
7.5.1 153 7/16/2026
7.5.0 151 7/15/2026
7.5.0-beta.114 83 7/15/2026
7.5.0-beta.113 81 7/15/2026
Loading failed