BB84.EntityFrameworkCore.Repositories.SqlServer
5.0.916
See the version list below for details.
dotnet add package BB84.EntityFrameworkCore.Repositories.SqlServer --version 5.0.916
NuGet\Install-Package BB84.EntityFrameworkCore.Repositories.SqlServer -Version 5.0.916
<PackageReference Include="BB84.EntityFrameworkCore.Repositories.SqlServer" Version="5.0.916" />
<PackageVersion Include="BB84.EntityFrameworkCore.Repositories.SqlServer" Version="5.0.916" />
<PackageReference Include="BB84.EntityFrameworkCore.Repositories.SqlServer" />
paket add BB84.EntityFrameworkCore.Repositories.SqlServer --version 5.0.916
#r "nuget: BB84.EntityFrameworkCore.Repositories.SqlServer, 5.0.916"
#:package BB84.EntityFrameworkCore.Repositories.SqlServer@5.0.916
#addin nuget:?package=BB84.EntityFrameworkCore.Repositories.SqlServer&version=5.0.916
#tool nuget:?package=BB84.EntityFrameworkCore.Repositories.SqlServer&version=5.0.916
BB84.EntityFrameworkCore.Repositories.SqlServer
This package provides the SQL Server tuning of the entity type configuration base classes, PropertyBuilderExtensions for column types, EntityTypeBuilderExtensions for temporal table support, and DatabaseFacadeExtensions for calling stored procedures and SQL functions.
Moved in 5.0. The configuration base classes now derive from provider-agnostic bases in
BB84.EntityFrameworkCore.Repositories, and the interceptors moved there outright.DatabaseFacadeExtensionsmoved the other way, into this package, because it emits T-SQL. See Package boundaries.
Installation
dotnet add package BB84.EntityFrameworkCore.Repositories.SqlServer
Package boundaries
Each configuration ladder exists twice, under the same type names:
| Namespace | Applies |
|---|---|
BB84.EntityFrameworkCore.Repositories.Configurations |
Key declaration, column order, concurrency token, audit columns, soft delete filter |
BB84.EntityFrameworkCore.Repositories.SqlServer.Configurations |
The above, plus clustering, NEWID() defaults and sysname audit columns |
Pick the namespace, not the type. On SQL Server, keep importing this package's namespace and nothing changes. On any other provider, import the agnostic one and you get everything except the three SQL Server calls.
A file that imports both namespaces — a project mapping a SQL Server context and a second provider's context side by side — hits CS0104 on the ambiguous name. Alias one of them:
using SqlServerConfigurations = BB84.EntityFrameworkCore.Repositories.SqlServer.Configurations;
Configuration base classes
Inherit from these in your IEntityTypeConfiguration<TEntity> implementations and call base.Configure(builder) to apply the standard column order, constraints, concurrency tokens, and indexes. Override before or after the base call to add entity-specific configuration.
| Configuration class | For entity type | What base.Configure applies |
|---|---|---|
IdentityConfiguration<TEntity, TKey> |
IIdentityEntity<TKey> |
Non-clustered PK, Id (ValueGeneratedOnAdd), Timestamp as concurrency token |
AuditedConfiguration<TEntity, TKey, TCreator, TEditor> |
IAuditedEntity<TKey, TCreator, TEditor> |
Above + CreatedBy (required), EditedBy (optional); the <TEntity, TKey> overload maps both as sysname, the <TEntity> overload adds the NEWID() default too |
FullAuditedConfiguration<TEntity, TKey, TCreator, TEditor> |
IFullAuditedEntity<TKey, TCreator, TEditor> |
Above + CreatedAt (required), EditedAt (optional); same overload behaviour |
CompositeConfiguration<TEntity> |
ICompositeEntity |
Timestamp as concurrency token |
AuditedCompositeConfiguration<TEntity, TCreator, TEditor> |
IAuditedCompositeEntity<TCreator, TEditor> |
Above + audit user columns |
EnumeratorConfiguration<TEntity, TKey> |
IEnumeratorEntity<TKey> |
Non-clustered PK, Name (nvarchar(64), unique index, non-unicode), Description (nvarchar(256)), IsDeleted default false; int overload uses clustered PK |
These stop at the byte[] rung on purpose. The token type is a parameter on the agnostic bases in BB84.EntityFrameworkCore.Repositories, but on SQL Server the concurrency token is a rowversion and a rowversion is eight bytes — there is nothing here for another type to map onto. An entity with a different token type belongs on the agnostic configuration bases.
public class ProductConfiguration : IdentityConfiguration<Product>
{
public override void Configure(EntityTypeBuilder<Product> builder)
{
base.Configure(builder);
builder.ToTable("Products", "catalog");
builder.Property(p => p.Name).IsRequired().HasMaxLength(200);
builder.Property(p => p.Price).IsDecimalColumn(10, 2);
}
}
public class InvoiceConfiguration : FullAuditedConfiguration<Invoice>
{
public override void Configure(EntityTypeBuilder<Invoice> builder)
{
base.Configure(builder); // applies NEWID() default, sysname for audit columns
builder.ToTable("Invoices", "billing");
builder.Property(i => i.Number).IsRequired().HasMaxLength(50);
}
}
public class ProductCategoryConfiguration : EnumeratorConfiguration<ProductCategory>
{
public override void Configure(EntityTypeBuilder<ProductCategory> builder)
{
base.Configure(builder); // clustered int PK, Name unique index, IsDeleted default false
builder.ToTable("ProductCategories", "catalog");
}
}
Apply configurations via ApplyConfigurationsFromAssembly in OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
PropertyBuilderExtensions
Extension methods that set the SQL Server column type in one call, each in two forms. The generic form extends PropertyBuilder<TProperty> and returns it unchanged, so the property type survives the call and anything typed later in the chain — HasDefaultValue, HasConversion, HasValueGenerator — stays compile-time checked. The non-generic form extends PropertyBuilder and exists for the Property(string) path used by shadow properties. A lambda-based Property call picks the generic form automatically.
builder.Property(e => e.Price) // PropertyBuilder<decimal>
.IsDecimalColumn(10, 2) // PropertyBuilder<decimal> — type kept
.HasDefaultValue(0m); // takes decimal, not object
| Method | SQL Server type | Parameters |
|---|---|---|
IsBinaryColumn(length) |
binary(n) |
length: 1–8000 (default 8000); binary has no max form |
IsDateColumn() |
date |
— |
IsDateTimeColumn(small) |
datetime / smalldatetime |
small: false → datetime |
IsDateTime2Column(precision) |
datetime2(n) |
precision: 0–7 (default 7) |
IsDateTimeOffsetColumn(precision) |
datetimeoffset(n) |
precision: 0–7 (default 7) |
IsDecimalColumn(precision, scale) |
decimal(p,s) |
precision: 1–38 (default 18), scale: 0–precision (default 2) |
IsMoneyColumn(small) |
money / smallmoney |
small: false → money |
IsSysNameColumn() |
sysname |
— |
IsTimeColumn(precision) |
time(n) |
precision: 0–7 (default 7) |
IsUniqueIdentifierColumn() |
uniqueidentifier |
— |
IsVarbinaryColumn(length) |
varbinary(n) / varbinary(max) |
length: 0–8000; 0 → varbinary(max) (default 0) |
IsXmlColumn() |
xml |
— |
Methods with a precision or length parameter throw ArgumentOutOfRangeException when the value is outside the valid range.
public class OrderConfiguration : IdentityConfiguration<Order>
{
public override void Configure(EntityTypeBuilder<Order> builder)
{
base.Configure(builder);
builder.ToTable("Orders", "sales");
builder.Property(o => o.TotalAmount)
.IsDecimalColumn(precision: 18, scale: 4);
builder.Property(o => o.PlacedAt)
.IsDateTimeOffsetColumn(precision: 3);
builder.Property(o => o.DueDate)
.IsDateColumn();
builder.Property(o => o.Notes)
.IsXmlColumn();
builder.Property(o => o.Attachment)
.IsVarbinaryColumn(); // varbinary(max)
}
}
EntityTypeBuilderExtensions
ToHistoryTable
One-line setup for SQL Server temporal tables with a separate history schema:
builder.ToHistoryTable(
tableName: "Orders", // defaults to entity class name
tableSchema: "sales", // defaults to "dbo"
historyTableName: "Orders", // defaults to tableName
historyTableSchema: "history" // defaults to "history"
);
Interceptors
SoftDeletableInterceptor and TimeAuditedInterceptor moved to BB84.EntityFrameworkCore.Repositories in 5.0 — nothing in them was SQL Server specific. Update the using to BB84.EntityFrameworkCore.Repositories.Interceptors; the types and their behavior are unchanged.
DatabaseFacadeExtensions
Extension methods on DatabaseFacade (context.Database) for calling SQL Server stored procedures and functions safely with parameterized SQL. These moved here from BB84.EntityFrameworkCore.Repositories in 5.0, because the SQL they emit — EXECUTE [schema].[name] @p = @p OUTPUT, SELECT [Value] = [schema].[fn](@p) — is T-SQL by construction.
Stored procedures
// Returns rows as IReadOnlyList<T>
IReadOnlyList<ReportRow> rows = context.Database.ExecuteProcedure<ReportRow>(
schema: "dbo",
name: "usp_GetReport",
parameters: [new SqlParameter("@FromDate", fromDate)]);
// Non-generic overload returns rows-affected count
int affected = context.Database.ExecuteProcedure(
schema: "dbo",
name: "usp_ArchiveOrders",
parameters: [new SqlParameter("@CutoffDate", cutoff)]);
// Async variants
await context.Database.ExecuteProcedureAsync<ReportRow>(..., cancellationToken);
await context.Database.ExecuteProcedureAsync(..., cancellationToken);
Output parameters are supported — parameters with Direction = ParameterDirection.Output are emitted as @param = @param OUTPUT in the generated SQL.
Table-valued functions
IReadOnlyList<ProductDto> results = context.Database.ExecuteTableFunction<ProductDto>(
schema: "dbo",
name: "fn_GetActiveProducts",
parameters: [new SqlParameter("@CategoryId", categoryId)]);
await context.Database.ExecuteTableFunctionAsync<ProductDto>(..., cancellationToken);
Scalar-valued functions
decimal? total = context.Database.ExecuteScalarFunction<decimal>(
schema: "dbo",
name: "fn_GetOrderTotal",
parameters: [new SqlParameter("@OrderId", orderId)]);
await context.Database.ExecuteScalarFunctionAsync<decimal>(..., cancellationToken);
All methods sanitize schema/name inputs and use parameterized SQL to prevent injection. The parameter sequence is materialized once on entry, so a lazily generated IEnumerable<DbParameter> is safe to pass.
| 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
- BB84.EntityFrameworkCore.Repositories (>= 5.0.916)
- Microsoft.EntityFrameworkCore.SqlServer (>= 10.0.12)
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 |
|---|---|---|
| 5.0.1020 | 91 | 10/20/2026 |
| 5.0.916 | 265 | 9/16/2026 |
| 5.0.818 | 272 | 8/18/2026 |
| 4.5.725 | 223 | 7/25/2026 |
| 4.4.724 | 139 | 7/24/2026 |
| 4.4.625 | 220 | 6/25/2026 |
| 4.3.520 | 322 | 5/20/2026 |
| 4.3.513 | 191 | 5/13/2026 |
| 4.3.507 | 161 | 5/7/2026 |
| 4.3.419 | 245 | 4/19/2026 |
| 4.3.327 | 287 | 3/27/2026 |
| 4.2.322 | 168 | 3/22/2026 |
| 4.1.319 | 138 | 3/19/2026 |
| 4.1.222 | 235 | 2/22/2026 |
| 4.1.122 | 206 | 1/22/2026 |
| 4.0.1026 | 416 | 10/26/2025 |
| 4.0.916 | 490 | 9/16/2025 |
| 4.0.817 | 305 | 8/17/2025 |
| 3.1.617 | 399 | 6/17/2025 |
| 3.1.518 | 276 | 5/18/2025 |