Pandatech.EFCore.PostgresExtensions
7.0.0
dotnet add package Pandatech.EFCore.PostgresExtensions --version 7.0.0
NuGet\Install-Package Pandatech.EFCore.PostgresExtensions -Version 7.0.0
<PackageReference Include="Pandatech.EFCore.PostgresExtensions" Version="7.0.0" />
<PackageVersion Include="Pandatech.EFCore.PostgresExtensions" Version="7.0.0" />
<PackageReference Include="Pandatech.EFCore.PostgresExtensions" />
paket add Pandatech.EFCore.PostgresExtensions --version 7.0.0
#r "nuget: Pandatech.EFCore.PostgresExtensions, 7.0.0"
#:package Pandatech.EFCore.PostgresExtensions@7.0.0
#addin nuget:?package=Pandatech.EFCore.PostgresExtensions&version=7.0.0
#tool nuget:?package=Pandatech.EFCore.PostgresExtensions&version=7.0.0
Pandatech.EFCore.PostgresExtensions
PostgreSQL-specific extensions for Entity Framework Core that fill the gaps left by the official Npgsql provider.
| Feature | What it does |
|---|---|
| Row-level locking | FOR UPDATE with Wait, SkipLocked, and NoWait behaviors |
| Random-increment IDs | Non-predictable sequential IDs backed by a PostgreSQL sequence |
| Natural sort keys | Human-friendly ordering for strings containing numbers |
| Schema rollback helpers | Clean Down() migration methods for all of the above |
Targets net8.0, net9.0, and net10.0.
Installation
dotnet add package Pandatech.EFCore.PostgresExtensions
Row-level locking
PostgreSQL's FOR UPDATE clause lets you lock selected rows for the duration of a transaction. This package exposes it
as a LINQ extension method with three lock behaviors.
Setup
Register the query interceptor on your DbContext:
services.AddDbContextPool<AppDbContext>(options =>
options.UseNpgsql(connectionString)
.UseQueryLocks());
Usage
The ForUpdate method must be called inside a transaction:
await using var transaction = await dbContext.Database.BeginTransactionAsync();
var order = await dbContext.Orders
.Where(o => o.Id == orderId)
.ForUpdate(LockBehavior.SkipLocked)
.FirstOrDefaultAsync();
// Modify the locked row
order.Status = OrderStatus.Processing;
await dbContext.SaveChangesAsync();
await transaction.CommitAsync();
Lock behaviors
| Behavior | SQL generated | When to use |
|---|---|---|
Default (Wait) |
FOR UPDATE |
You need the row and can wait for it |
SkipLocked |
FOR UPDATE SKIP LOCKED |
Queue-style processing — skip rows another worker already holds |
NoWait |
FOR UPDATE NOWAIT |
Fail immediately if the row is locked |
Random-increment sequence IDs
Generates bigint IDs that increment by a random amount within a configurable range. The IDs are unique and always
increasing, but the gaps between them are unpredictable — preventing enumeration attacks while keeping an index-friendly
insert order.
1. Configure the entity
public class Animal
{
public long Id { get; set; }
public string Name { get; set; }
}
public class AnimalConfiguration : IEntityTypeConfiguration<Animal>
{
public void Configure(EntityTypeBuilder<Animal> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasRandomIdSequence();
}
}
2. Create the function in a migration
The function must be created before the table that references it. Add it manually at the top of your Up() method:
protected override void Up(MigrationBuilder migrationBuilder)
{
// Create the sequence + function first
migrationBuilder.CreateRandomIdSequence(
tableName: "animal",
pkName: "id",
startValue: 5,
minRandIncrementValue: 5,
maxRandIncrementValue: 10);
// Then create the table (the default value references the function)
migrationBuilder.CreateTable(...);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropRandomIdSequence("animal", "id");
migrationBuilder.DropTable("animal");
}
Parameters: startValue is the first ID returned, minRandIncrementValue and maxRandIncrementValue define the random
gap range between consecutive IDs.
Natural sort keys
Sorts strings that contain numbers the way a human would expect: "Item 2" before "Item 10", not after it. The
package creates a PostgreSQL function that zero-pads numeric substrings, producing a sortable text key.
1. Create the function (once per database)
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateNaturalSortKeyFunction();
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropNaturalSortKeyFunction();
}
2. Add a computed column
public class Building
{
public long Id { get; set; }
public string Address { get; set; }
public string AddressNaturalSortKey { get; set; }
}
public class BuildingConfiguration : IEntityTypeConfiguration<Building>
{
public void Configure(EntityTypeBuilder<Building> builder)
{
builder.Property(x => x.AddressNaturalSortKey)
.HasNaturalSortKey("address");
}
}
Then order by the computed column:
var sorted = await dbContext.Buildings
.OrderBy(b => b.AddressNaturalSortKey)
.ToListAsync();
Encrypted-column unique indexes
For columns that store encrypted data where only the first 64 characters are deterministic (e.g., hash prefix), you can create a unique index on that prefix:
// In migration Up()
migrationBuilder.CreateUniqueIndexOnEncryptedColumn("users", "email_encrypted");
// With an optional WHERE condition
migrationBuilder.CreateUniqueIndexOnEncryptedColumn("users", "email_encrypted", "is_active = true");
// In migration Down()
migrationBuilder.DropUniqueIndexOnEncryptedColumn("users", "email_encrypted");
API reference
Extension methods
| Method | Target | Description |
|---|---|---|
UseQueryLocks() |
DbContextOptionsBuilder |
Registers the interceptor that rewrites tagged queries into FOR UPDATE SQL |
ForUpdate() |
IQueryable<T> |
Tags a query for row-level locking (must be inside a transaction) |
HasRandomIdSequence() |
PropertyBuilder |
Configures the property to use a random-increment sequence as its default value |
HasNaturalSortKey(column) |
PropertyBuilder |
Configures the property as a stored computed column using the natural sort function |
CreateRandomIdSequence(...) |
MigrationBuilder |
Creates the PostgreSQL sequence and generator function |
DropRandomIdSequence(...) |
MigrationBuilder |
Drops the sequence and generator function |
CreateNaturalSortKeyFunction() |
MigrationBuilder |
Creates the natural sort key function |
DropNaturalSortKeyFunction() |
MigrationBuilder |
Drops the natural sort key function |
CreateUniqueIndexOnEncryptedColumn(...) |
MigrationBuilder |
Creates a unique index on the first 64 chars of a column |
DropUniqueIndexOnEncryptedColumn(...) |
MigrationBuilder |
Drops the encrypted-column unique index |
Enums
LockBehavior: Default (wait), SkipLocked, NoWait.
License
MIT
| 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 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
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 10.0.0)
-
net8.0
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 8.0.0)
-
net9.0
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 9.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Pandatech.EFCore.PostgresExtensions:
| Package | Downloads |
|---|---|
|
Pandatech.SharedKernel.Postgres
Pandatech.SharedKernel.Postgres simplifies PostgreSQL integration in ASP.NET Core applications by providing utilities for Entity Framework Core setup, health checks, and other enhancements. |
|
|
Pandatech.MassTransit.PostgresOutbox
Pandatech.MassTransit.PostgresOutbox extends MassTransit to offer advanced message handling capabilities for distributed systems. With first-class support for multiple DbContexts, this library integrates seamlessly with Entity Framework Core and PostgreSQL, providing reliable Outbox and Inbox patterns. It ensures consistent message delivery and processing in complex microservices architectures, leveraging PostgreSQL's ForUpdate feature to handle concurrency with ease. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 7.0.0 | 0 | 2/28/2026 |
| 6.2.0 | 154 | 2/21/2026 |
| 6.1.0 | 1,931 | 1/26/2026 |
| 6.0.0 | 512 | 12/28/2025 |
| 5.1.3 | 17,571 | 8/7/2025 |
| 5.1.2 | 348 | 6/1/2025 |
| 5.1.1 | 243 | 5/6/2025 |
| 5.1.0 | 346 | 3/31/2025 |
| 5.0.0 | 230 | 3/31/2025 |
| 4.0.2 | 361 | 3/12/2025 |
| 4.0.1 | 667 | 2/17/2025 |
| 4.0.0 | 2,053 | 11/21/2024 |
| 3.0.0 | 19,049 | 7/17/2024 |
| 2.0.1 | 343 | 5/26/2024 |
| 2.0.0 | 203 | 4/10/2024 |
| 1.0.0 | 382 | 3/29/2024 |
Multi-TFM support (net8/9/10), improved documentation