Pandatech.GridifyExtensions 4.0.0

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

Pandatech.GridifyExtensions

Extensions for Gridify providing streamlined filtering, ordering, pagination, and aggregation for .NET 8+ with Entity Framework Core.

Installation

dotnet add package Pandatech.GridifyExtensions

Setup

Register Gridify with custom mapper discovery:

builder.AddGridify(); // Scans calling assembly
// or
builder.AddGridify(typeof(Program).Assembly, typeof(Domain).Assembly);

Quick Start

1. Define Entity Mapper

public class Book
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public DateTime PublishedDate { get; set; }
    public decimal Price { get; set; }
}

public class BookMapper : FilterMapper<Book>
{
    public BookMapper()
    {
        GenerateMappings(); // Auto-map all properties
        
        // Custom mappings
        AddMap("book-id", x => x.Id);
        AddMap("title", x => x.Title.ToLower(), x => x.ToLower());
        AddMap("published", x => x.PublishedDate, x => x.ToUtcDateTime());
        
        // Default sort order
        AddDefaultOrderByDescending("published");
    }
}

2. Query with Filtering & Pagination

// Paged response
var result = await dbContext.Books
    .FilterOrderAndGetPagedAsync(
        new GridifyQueryModel { 
            Page = 1, 
            PageSize = 20,
            Filter = "title=*potter*",
            OrderBy = "published desc"
        },
        cancellationToken
    );

// With projection
var dtos = await dbContext.Books
    .FilterOrderAndGetPagedAsync(
        new GridifyQueryModel { Page = 1, PageSize = 20 },
        x => new BookDto { Title = x.Title, Price = x.Price },
        cancellationToken
    );

3. Cursor-Based Pagination

var result = await dbContext.Books
    .FilterOrderAndGetCursoredAsync(
        new GridifyCursoredQueryModel { 
            PageSize = 50,
            Filter = "price>10"
        },
        cancellationToken
    );

Core Features

Filtering & Ordering

// Apply filter only
var filtered = query.ApplyFilter("title=*science*");

// Apply filter from model
var filtered = query.ApplyFilter(new GridifyQueryModel { Filter = "price<20" });

// Apply ordering
var ordered = query.ApplyOrder(new GridifyQueryModel { OrderBy = "title" });

Pagination

// Traditional paging
var paged = await query.GetPagedAsync(
    new GridifyQueryModel { Page = 2, PageSize = 10 },
    cancellationToken
);

// Cursor-based (more efficient for large datasets)
var cursored = await query.FilterOrderAndGetCursoredAsync(
    new GridifyCursoredQueryModel { PageSize = 50 },
    cancellationToken
);

Column Distinct Values

// Get distinct values for a column (with cursor pagination)
var distinctTitles = await dbContext.Books
    .ColumnDistinctValuesAsync(
        new ColumnDistinctValueCursoredQueryModel { 
            PropertyName = "title",
            PageSize = 50,
            Filter = "title>A"
        },
        cancellationToken
    );

// For encrypted columns, provide decryptor
var decrypted = await query.ColumnDistinctValuesAsync(
    model,
    decryptor: bytes => Decrypt(bytes),
    cancellationToken
);

Aggregations

var total = await dbContext.Books
    .AggregateAsync(
        new AggregateQueryModel { 
            AggregateType = AggregateType.Sum,
            PropertyName = "price"
        },
        cancellationToken
    );

Supported aggregations:

  • UniqueCount - Count of distinct values
  • Sum - Sum of values
  • Average - Average value
  • Min - Minimum value
  • Max - Maximum value

Advanced Features

Custom Converters

public class DeviceMapper : FilterMapper<Device>
{
    public DeviceMapper()
    {
        GenerateMappings();
        
        // Case-insensitive string matching
        AddMap("name", x => x.Name.ToLower(), x => x.ToLower());
        
        // DateTime with UTC conversion
        AddMap("created", x => x.CreatedAt, x => x.ToUtcDateTime());
        
        AddDefaultOrderByDescending("created");
    }
}

Encrypted Columns

public class UserMapper : FilterMapper<User>
{
    public UserMapper()
    {
        // Mark column as encrypted
        AddMap("email", x => x.EncryptedEmail, isEncrypted: true);
    }
}

// Query with decryption
var users = await dbContext.Users
    .ColumnDistinctValuesAsync(
        new ColumnDistinctValueCursoredQueryModel { PropertyName = "email" },
        decryptor: encryptedBytes => AesDecrypt(encryptedBytes),
        cancellationToken
    );

Complex Mappings

// Navigation properties
AddMap("author-name", x => x.Author.Name);

// Collections
AddMap("tags", x => x.Tags.Select(t => t.Name));

// Nested properties
AddMap("publisher-country", x => x.Publisher.Address.Country);

Page Size Limits

By default, GridifyQueryModel limits PageSize to 500:

// Remove limit via constructor
var model = new GridifyQueryModel(validatePageSize: false) { 
    PageSize = 1000, 
    Page = 1 
};

// Or set to maximum
model.SetMaxPageSize(); // Sets PageSize to int.MaxValue

Custom Flag Operator

Built-in support for bitwise flag checking:

// Filter by enum flags
var query = "permissions#hasFlag16"; // checks if bit 16 is set

Gridify Query Syntax

Standard Gridify filtering syntax is supported:

// Operators: =, !=, <, >, <=, >=, =*, *=, =*=
Filter = "title=*potter*, price<20, published>2020-01-01"

// Logical: , (AND), | (OR), () (grouping)
Filter = "(title=*fantasy*|title=*scifi*), price<30"

// Custom operators
Filter = "flags#hasFlag4" // bitwise flag check

API Reference

Extension Methods

Method Description
ApplyFilter(model/filter) Apply filtering
ApplyOrder(model) Apply ordering
GetPagedAsync(model) Get paged results
FilterOrderAndGetPagedAsync(model) Filter + order + page
FilterOrderAndGetCursoredAsync(model) Cursor-based pagination
ColumnDistinctValuesAsync(model) Get distinct column values
AggregateAsync(model) Perform aggregation

Model Types

  • GridifyQueryModel - Traditional pagination with page number
  • GridifyCursoredQueryModel - Cursor-based pagination
  • ColumnDistinctValueCursoredQueryModel - Distinct values with cursor
  • AggregateQueryModel - Aggregation configuration

Response Types

  • PagedResponse<T> - (Data, Page, PageSize, TotalCount)
  • CursoredResponse<T> - (Data, PageSize)

License

MIT

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

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Pandatech.GridifyExtensions:

Package Downloads
Pandatech.ResponseCrafter

Exception-based error handling for ASP.NET Core 8+ with RFC 9457 ProblemDetails, structured logging, typed exceptions, automatic EF Core/Gridify/FluentImporter exception mapping, SignalR support, and flexible naming conventions. Alternative to Result pattern libraries.

Pandatech.SharedKernel.Postgres

PostgreSQL integration helpers for ASP.NET Core 10: DbContext registration with or without pooling and audit trail, migrations, health checks, snake_case naming, query locks, exception mapping, and bulk extensions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.0 137 2/28/2026
3.0.1 163 1/26/2026
3.0.0 127 12/28/2025
2.1.6 214 12/14/2025
2.1.5 231 12/5/2025
2.1.4 294 10/13/2025
2.1.3 210 10/13/2025
2.1.2 180 9/26/2025
2.1.1 260 9/21/2025
2.1.0 217 9/11/2025
2.0.14 309 8/15/2025
2.0.13 207 8/14/2025
2.0.12 204 8/14/2025
2.0.11 199 8/14/2025
2.0.10 191 8/14/2025
2.0.9 277 8/7/2025
2.0.8 325 6/1/2025
2.0.7 240 5/7/2025
2.0.6 217 4/11/2025
2.0.5 274 4/1/2025
Loading failed

Multi-target net8.0/9.0/10.0, framework-first dependencies, performance improvements, fixed extension method syntax