eQuantic LINQ Extensions
Advanced LINQ extensions and query utilities
Version: 2.1.0
Downloads: 32K+
Status: stable
Category: utilities
Installation
dotnet add package eQuantic.Linq

Overview
eQuantic.Linq is a modern and powerful library that extends LINQ capabilities for .NET applications, providing advanced tools for data querying, filtering, sorting, and business logic composition. The library implements sophisticated design patterns such as the Specification Pattern and Entity Filter/Sorter patterns, allowing developers to create maintainable and testable code.
This library supports both .NET (C#) and TypeScript implementations, maintaining feature parity between both platforms. It includes advanced features such as source generators for compile-time code generation, expression caching for performance optimization, async support for modern applications, and a comprehensive type-safe casting system.
eQuantic.Linq is designed with enterprise applications in mind, providing robust solutions for complex data operations while maintaining clean architecture principles. It enables separation of concerns by delegating filtering and sorting logic from the presentation layer to the service layer, promoting better code organization and testability.
Quick Start
1. Basic Installation and Setup
Install the eQuantic.Linq package in your .NET project and configure the necessary dependencies. The package supports multiple .NET versions including .NET Standard 2.1, .NET 6, 7, and 8.
// Install via Package Manager Console
Install-Package eQuantic.Linq
// Or via .NET CLI
dotnet add package eQuantic.Linq
// Basic using statements
using eQuantic.Linq.Specification;
using eQuantic.Linq.Filter;
using eQuantic.Linq.Sorter;
using eQuantic.Linq.Extensions;
2. Creating and Using Specifications
Specifications allow you to encapsulate business rules in reusable components. You can create custom specifications by inheriting from the Specification<T> base class and combining them using logical operators.
// Custom specification implementation
public class ActiveUserSpecification : Specification<User>
{
public override Expression<Func<User, bool>> SatisfiedBy()
{
return user => user.IsActive && user.EmailVerified;
}
}
// Using specifications with logical operators
var activeAdminSpec = new ActiveUserSpecification() &&
new AdminUserSpecification();
// Applying specifications to queries
var activeAdminUsers = users.Where(activeAdminSpec.SatisfiedBy());
// Direct specification usage
var isActiveAdmin = activeAdminSpec.IsSatisfiedBy(user);
3. Implementing Entity Filters for Clean Architecture
Entity filters provide a clean way to separate filtering logic from your controllers. They enable you to pass complex filtering criteria from the presentation layer to the service layer without coupling.
// Service layer method with entity filter
public async Task<List<Product>> GetProductsAsync(IEntityFilter<Product> filter)
{
var query = dbContext.Products.AsQueryable();
if (filter != null)
{
query = filter.Filter(query);
}
return await query.ToListAsync();
}
// Controller usage with fluent API
var filter = EntityFilter<Product>
.Where(p => p.Category == "Electronics")
.And(p => p.Price > 100)
.And(p => p.InStock);
var products = await productService.GetProductsAsync(filter);
// Complex filtering with nested conditions
var complexFilter = EntityFilter<Product>
.Where(p => p.Category == "Electronics" || p.Category == "Computers")
.And(p => p.Price >= minPrice && p.Price <= maxPrice)
.And(p => p.Reviews.Any(r => r.Rating >= 4));
4. Using Entity Sorters for Flexible Sorting
Entity sorters provide a flexible way to handle sorting logic, allowing you to define complex sorting criteria that can be easily modified and tested. They support multi-column sorting and custom sorting expressions.
// Service layer method with entity sorter
public async Task<List<Product>> GetSortedProductsAsync(IEntitySorter<Product> sorter)
{
var query = dbContext.Products.AsQueryable();
if (sorter != null)
{
query = sorter.Sort(query);
}
return await query.ToListAsync();
}
// Creating multi-level sorting
var sorter = EntitySorter<Product>
.OrderByDescending(p => p.Featured)
.ThenBy(p => p.Price)
.ThenByDescending(p => p.CreatedDate);
var sortedProducts = await productService.GetSortedProductsAsync(sorter);
// Dynamic sorting based on user input
var dynamicSorter = EntitySorter<Product>.OrderBy(p => p.Name);
if (sortByPrice)
{
dynamicSorter = dynamicSorter.ThenBy(p => p.Price);
}
if (sortByRating)
{
dynamicSorter = dynamicSorter.ThenByDescending(p => p.AverageRating);
}
5. Type-safe Casting with FluentCastBuilder
The casting system allows you to safely transform objects between different types with customizable mapping rules. It supports automatic property mapping, custom transformations, and validation.
// Basic casting with automatic property mapping
var productDto = product.Cast<ProductDto>();
// Custom mapping configuration
var productDto = product.Cast<ProductDto>(options =>
{
options.Map(src => src.ProductName, dest => dest.Name);
options.Map(src => src.UnitPrice, dest => dest.Price);
options.CustomMap(src => src.Category.Name, dest => dest.CategoryName);
options.ExcludeUnmapped();
});
// Collection casting
var productDtos = products.Cast<ProductDto>(options =>
{
options.Map(src => src.ProductName, dest => dest.Name);
options.Map(src => src.CreatedDate, dest => dest.CreatedAt);
});
// Complex mapping with nested objects
var orderDto = order.Cast<OrderDto>(options =>
{
options.Map(src => src.Customer.FullName, dest => dest.CustomerName);
options.Map(src => src.OrderItems.Sum(oi => oi.Total), dest => dest.TotalAmount);
options.CustomMap(src => src.OrderDate.ToString("yyyy-MM-dd"), dest => dest.FormattedDate);
});
6. Source Generators for Automatic Code Generation
Use source generators to automatically create specifications, filters, and sorting classes at compile time. This reduces boilerplate code and improves performance by eliminating reflection.
// Model with source generator attributes
[GenerateSpecifications]
public class Product
{
public int Id { get; set; }
[SpecProperty(FilterOperator.Equal | FilterOperator.Contains)]
public string Name { get; set; }
[SpecProperty(FilterOperator.Equal | FilterOperator.GreaterThan | FilterOperator.LessThan)]
public decimal Price { get; set; }
[SpecProperty(FilterOperator.Equal)]
public bool InStock { get; set; }
[SpecProperty(FilterOperator.Equal | FilterOperator.Contains)]
public string Category { get; set; }
}
// Generated code usage (automatically created by source generator)
var nameSpec = ProductSpecifications.NameContains("laptop");
var priceSpec = ProductSpecifications.PriceGreaterThan(500m);
var categorySpec = ProductSpecifications.CategoryEqual("Electronics");
// Combine generated specifications
var combinedSpec = nameSpec && priceSpec && categorySpec;
var filteredProducts = products.Where(combinedSpec.SatisfiedBy());
7. Advanced Async Operations
Leverage async support for non-blocking operations in modern applications. The library provides async versions of all major operations for better scalability.
// Async entity filter usage
public class ProductService
{
public async Task<PagedResult<Product>> GetProductsAsync(
IAsyncEntityFilter<Product> filter,
int page = 1,
int pageSize = 10)
{
var query = dbContext.Products.AsQueryable();
if (filter != null)
{
query = await filter.FilterAsync(query);
}
var totalCount = await query.CountAsync();
var items = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PagedResult<Product>
{
Items = items,
TotalCount = totalCount,
CurrentPage = page,
PageSize = pageSize
};
}
}
// Async specification evaluation
var activeUserSpec = new ActiveUserSpecification();
var user = await dbContext.Users.FirstOrDefaultAsync(activeUserSpec.SatisfiedBy());
8. Collection Filtering (Any/All) - v2.1+ Advanced Collection Queries
The Any/All functionality (new in v2.1+) revolutionizes how you work with collections in your queries. Imagine scenarios where you need to filter users who have ANY admin role, or find projects where ALL tasks are complete. This feature brings the power of LINQ Any() and All() to your dynamic queries, allowing you to express complex conditions on one-to-many relationships in a type-safe and performant way.
// ===== EXAMPLE MODELS =====
// Typical real-world application structures with relationships
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public List<Role> Roles { get; set; } = new();
public List<Project> Projects { get; set; } = new();
}
public class Role
{
public string Name { get; set; } = string.Empty;
public bool IsActive { get; set; }
public List<string> Permissions { get; set; } = new();
}
public class Project
{
public string Name { get; set; } = string.Empty;
public string Status { get; set; } = string.Empty;
public int Priority { get; set; }
public bool IsCompleted { get; set; }
public DateTime AssignedAt { get; set; }
}
// ===== ANY - ANY ITEM SATISFIES THE CONDITION =====
// Scenario 1: Users with ANY administrative role
// Useful for authorization systems
var adminOrManagerUsers = new CompositeFiltering<User>(
CompositeOperator.Any,
u => u.Roles,
"Name:eq(Admin)",
"Name:eq(Manager)",
"Name:eq(SuperAdmin)"
);
// Scenario 2: Users with ANY high-priority project
// Ideal for management dashboards
var highPriorityUsers = new CompositeFiltering<User>(
CompositeOperator.Any,
u => u.Projects,
"Priority:gte(8)",
"Status:eq(Critical)"
);
// ===== ALL - ALL ITEMS MUST SATISFY =====
// Scenario 3: Users where ALL projects are completed
// Perfect for productivity reports
var usersWithCompletedProjects = new CompositeFiltering<User>(
CompositeOperator.All,
u => u.Projects,
"Status:eq(Completed)",
"IsCompleted:eq(true)"
);
// Scenario 4: Users where ALL roles are active
// Important for security auditing
var usersWithActiveRoles = new CompositeFiltering<User>(
CompositeOperator.All,
u => u.Roles,
"IsActive:eq(true)"
);
// ===== COMPLEX QUERIES WITH NESTED CONDITIONS =====
// Scenario 5: Users with any role that has write permissions
var writePermissionUsers = new CompositeFiltering<User>(
CompositeOperator.Any,
u => u.Roles,
"Permissions:ct(write)",
"Permissions:ct(admin)",
"and(Name:eq(Editor),IsActive:eq(true))"
);
// Scenario 6: Users with all active and high-priority projects
var qualityFocusedUsers = new CompositeFiltering<User>(
CompositeOperator.All,
u => u.Projects,
"Status:neq(Cancelled)",
"Priority:gte(5)",
"AssignedAt:gte(2024-01-01)"
);
// ===== PRACTICAL APPLICATION IN SERVICES =====
public class UserManagementService
{
private readonly IRepository<User> _userRepository;
/// <summary>
/// Find active system administrators
/// </summary>
public async Task<List<User>> GetActiveAdministratorsAsync()
{
var adminFilter = new CompositeFiltering<User>(
CompositeOperator.Any,
u => u.Roles,
"Name:eq(Admin)",
"Name:eq(SuperAdmin)",
"and(Name:eq(Manager),IsActive:eq(true))"
);
return await adminFilter.Filter(_userRepository.Query())
.Where(u => u.IsActive)
.ToListAsync();
}
/// <summary>
/// Find users who completed all their projects (for bonuses)
/// </summary>
public async Task<List<User>> GetTopPerformersAsync()
{
var completedProjectsFilter = new CompositeFiltering<User>(
CompositeOperator.All,
u => u.Projects,
"Status:eq(Completed)",
"IsCompleted:eq(true)"
);
return await completedProjectsFilter.Filter(_userRepository.Query())
.Where(u => u.Projects.Count > 0) // Only users with projects
.Include(u => u.Projects)
.ToListAsync();
}
}
// ===== STRING QUERY FORMAT - DYNAMIC PARSING =====
// The functionality supports parsing string queries for dynamic APIs
// Format: "Property:operator(conditions)"
// Parse Any query
var anyRoleFilter = CompositeFiltering.ParseComposite(
"Roles:any(Name:eq(Admin),IsActive:eq(true),Permissions:ct(write))"
);
// Parse All query
var allProjectFilter = CompositeFiltering.ParseComposite(
"Projects:all(Status:neq(Cancelled),Priority:gte(5),IsCompleted:eq(false))"
);
// ===== INTEGRATION WITH ASYNC OPERATIONS =====
// Works perfectly with asynchronous operations
var users = await Query.For<User>()
.Where(u => u.IsActive)
.Where(adminOrManagerUsers) // Apply collection filter
.OrderByDescending(u => u.LastLoginAt)
.ApplyToAsync(dbContext.Users, cancellationToken);
// Stream processing for large volumes
await foreach (var user in Query.For<User>()
.Where(u => u.CreatedAt > DateTime.Now.AddYears(-1))
.Where(usersWithCompletedProjects)
.ApplyToAsyncEnumerable(dbContext.Users, cancellationToken))
{
await ProcessUserAsync(user);
}
9. Modern CastWith() System - v2.0+
This is one of the most revolutionary features of version 2.0+. The CastWith() method with FluentCastBuilder enables transformation of filters, sortings, and objects between different models with optimized performance through expression caching. This is especially useful in microservice architectures, public APIs, and integrations where you receive data in one format and need to apply it to another model.
// ===== FILTER CASTING =====
// Transform generic filters (from external APIs, frontend, etc.)
// into type-safe filters for your entities
var dtoFilters = new IFiltering[]
{
new Filtering("productName", "Laptop", FilterOperator.Contains),
new Filtering("minPrice", "500", FilterOperator.GreaterThan),
new Filtering("category", "Electronics", FilterOperator.Equals),
new Filtering("isAvailable", "true", FilterOperator.Equals)
};
// CastWith() performs type-safe transformation with FluentCastBuilder
var entityFilters = dtoFilters.CastWith<Product>(builder => builder
.MapFilter("productName", p => p.Name) // Maps "productName" -> Product.Name
.MapFilter("minPrice", p => p.Price, value => decimal.Parse(value)) // + conversion
.MapFilter("category", p => p.Category)
.MapFilter("isAvailable", p => p.IsActive, value => bool.Parse(value))
.ExcludeUnmapped()); // Ignores unmapped filters (safety)
// Apply the transformed filters
var products = await repository.GetAsync(entityFilters.ToSpecification());
// ===== SORTING CASTING =====
// Same concept for sorting
var dtoSortings = new ISorting[]
{
new Sorting("displayName", SortDirection.Ascending),
new Sorting("createdDate", SortDirection.Descending)
};
var entitySortings = dtoSortings.CastWith<Product>(builder => builder
.MapSorting("displayName", p => p.Name)
.MapSorting("createdDate", p => p.CreatedAt));
// ===== SIMPLE OBJECT CASTING =====
// Transform DTOs to entities or vice versa
var productDto = new ProductDto
{
ProductName = "Gaming Laptop",
UnitPrice = 1299.99m,
CategoryName = "Electronics",
Available = true
};
// CastWith() for simple objects too
var product = productDto.CastWith<Product>(builder => builder
.Map(dto => dto.ProductName, entity => entity.Name)
.Map(dto => dto.UnitPrice, entity => entity.Price)
.Map(dto => dto.Available, entity => entity.IsActive)
.CustomMap(dto => dto.CategoryName, entity => entity.Category,
categoryName => new Category { Name = categoryName })
.ExcludeUnmapped());
// ===== CASTWITH() BENEFITS =====
// 1. PERFORMANCE: Expressions are automatically cached
// 2. TYPE SAFETY: Errors detected at compile time
// 3. MEMORY EFFICIENT: Lower memory allocation
// 4. INTUITIVE API: Fluent and discoverable interface
// ===== COMPARING WITH TRADITIONAL METHOD =====
// Traditional Cast() method still works (backward compatibility)
var productLegacy = productDto.Cast<Product>(options =>
{
options.Map(dto => dto.ProductName, entity => entity.Name);
options.Map(dto => dto.UnitPrice, entity => entity.Price);
options.ExcludeUnmapped();
});
// But CastWith() offers better performance and cleaner API
API Reference
ISpecification<T>
Core interface for implementing the Specification Pattern. Provides methods for composing business rules that can be combined and reused throughout your application.
public class ExpensiveProductSpecification : ISpecification<Product>
{
public Expression<Func<Product, bool>> SatisfiedBy()
{
return product => product.Price > 1000;
}
public bool IsSatisfiedBy(Product entity)
{
return entity.Price > 1000;
}
}
Specification<T>
Abstract base class for creating custom specifications. Provides built-in support for logical operations (AND, OR, NOT) and composition methods for building complex business rules.
public class ActiveUserSpecification : Specification<User>
{
public override Expression<Func<User, bool>> SatisfiedBy()
{
return user => user.IsActive && !user.IsDeleted;
}
}
// Usage with logical operators
var activeAdminSpec = new ActiveUserSpecification() && new AdminUserSpecification();
var result = activeAdminSpec.IsSatisfiedBy(user);
IEntityFilter<TEntity>
Interface for implementing entity filtering logic. Enables clean separation between presentation and business logic by allowing controllers to pass filtering criteria to service methods.
public async Task<List<Product>> GetFilteredProductsAsync(IEntityFilter<Product> filter)
{
var query = dbContext.Products.AsQueryable();
if (filter != null)
{
query = filter.Filter(query);
}
return await query.ToListAsync();
}
EntityFilter<TEntity>
Concrete implementation of IEntityFilter<TEntity> that provides a fluent API for building complex filtering expressions. Supports method chaining and logical operations for creating sophisticated queries.
// Fluent API for complex filtering
var filter = EntityFilter<Product>
.Where(p => p.Category == "Electronics")
.And(p => p.Price >= 100 && p.Price <= 1000)
.And(p => p.InStock)
.And(p => p.Reviews.Any(r => r.Rating >= 4));
var products = await productService.GetProductsAsync(filter);
IEntitySorter<TEntity>
Interface for implementing entity sorting logic. Provides a clean way to handle sorting operations while maintaining separation of concerns between presentation and business layers.
public async Task<List<Product>> GetSortedProductsAsync(IEntitySorter<Product> sorter)
{
var query = dbContext.Products.AsQueryable();
if (sorter != null)
{
query = sorter.Sort(query);
}
return await query.ToListAsync();
}
EntitySorter<TEntity>
Concrete implementation of IEntitySorter<TEntity> that provides a fluent API for building complex sorting expressions. Supports multi-level sorting with OrderBy, ThenBy operations and custom sorting logic.
// Multi-level sorting with fluent API
var sorter = EntitySorter<Product>
.OrderByDescending(p => p.Featured)
.ThenBy(p => p.Category)
.ThenByDescending(p => p.Price)
.ThenBy(p => p.Name);
var sortedProducts = await productService.GetSortedProductsAsync(sorter);
FluentCastBuilder<TSource, TDestination>
Modern casting system (v2.0+) that provides type-safe transformation with optimized performance, expression caching, and an intuitive fluent API. Replaces the traditional casting system with significant performance and type safety improvements.
// Modern usage with CastWith() and FluentCastBuilder (v2.0+)
var orderDto = order.CastWith<OrderDto>(builder => builder
.Map(src => src.Customer.FullName, dest => dest.CustomerName)
.Map(src => src.CreatedDate, dest => dest.OrderDate)
.CustomMap(src => src.OrderItems.Sum(oi => oi.Total), dest => dest.TotalAmount)
.ExcludeUnmapped());
// Filter casting - new functionality
var entityFilters = dtoFilters.CastWith<User>(builder => builder
.MapFilter("name", u => u.FullName)
.MapFilter("age", u => u.Age, value => int.Parse(value))
.ExcludeUnmapped());
// Sorting casting - new functionality
var entitySortings = dtoSortings.CastWith<User>(builder => builder
.MapSorting("created", u => u.CreatedDate)
.MapSorting("displayName", u => u.FullName));
IExpressionCache
Interface for caching compiled lambda expressions to improve performance in scenarios with repeated query operations. Stores expressions in memory and provides efficient retrieval mechanisms.
// Expression caching for performance
public class ProductRepository
{
private readonly IExpressionCache _expressionCache;
public IQueryable<Product> GetActiveProducts()
{
var cachedExpression = _expressionCache.GetOrAdd(
"ActiveProducts",
() => (Expression<Func<Product, bool>>)(p => p.IsActive));
return dbContext.Products.Where(cachedExpression);
}
}
GenerateSpecificationsAttribute
Source generator attribute that automatically creates specification classes at compile time. Reduces boilerplate code and improves performance by eliminating reflection-based operations.
[GenerateSpecifications]
public class User
{
[SpecProperty(FilterOperator.Equal | FilterOperator.Contains)]
public string Name { get; set; }
[SpecProperty(FilterOperator.Equal)]
public bool IsActive { get; set; }
}
// Generated specifications usage
var nameSpec = UserSpecifications.NameContains("John");
var activeSpec = UserSpecifications.IsActiveEqual(true);
var combinedSpec = nameSpec && activeSpec;
SpecPropertyAttribute
Attribute used with source generators to specify which filter operations should be generated for a property. Supports various filter operators including Equal, Contains, GreaterThan, LessThan, and more.
public class Product
{
[SpecProperty(FilterOperator.Equal | FilterOperator.Contains)]
public string Name { get; set; }
[SpecProperty(FilterOperator.GreaterThan | FilterOperator.LessThan | FilterOperator.Equal)]
public decimal Price { get; set; }
[SpecProperty(FilterOperator.Equal)]
public ProductCategory Category { get; set; }
}
FilterOperator
Enumeration that defines the available filter operations for source generator attributes. Supports bitwise combinations to specify multiple operations for a single property.
// Available filter operators
FilterOperator.Equal // Generates equality comparisons
FilterOperator.NotEqual // Generates inequality comparisons
FilterOperator.Contains // Generates string contains operations
FilterOperator.StartsWith // Generates string starts with operations
FilterOperator.EndsWith // Generates string ends with operations
FilterOperator.GreaterThan // Generates greater than comparisons
FilterOperator.LessThan // Generates less than comparisons
FilterOperator.GreaterEqual // Generates greater than or equal comparisons
FilterOperator.LessEqual // Generates less than or equal comparisons
IAsyncEntityFilter<TEntity>
Async version of IEntityFilter that provides non-blocking filtering operations. Essential for modern applications that require scalable data access patterns and responsive user interfaces.
public class AsyncProductService
{
public async Task<PagedResult<Product>> SearchProductsAsync(
IAsyncEntityFilter<Product> filter,
CancellationToken cancellationToken = default)
{
var query = dbContext.Products.AsQueryable();
if (filter != null)
{
query = await filter.FilterAsync(query, cancellationToken);
}
return await query.ToPagedResultAsync(cancellationToken);
}
}
IAsyncEntitySorter<TEntity>
Async version of IEntitySorter that provides non-blocking sorting operations. Enables efficient data sorting in high-throughput applications without blocking the main execution thread.
public class AsyncProductService
{
public async Task<List<Product>> GetSortedProductsAsync(
IAsyncEntitySorter<Product> sorter,
CancellationToken cancellationToken = default)
{
var query = dbContext.Products.AsQueryable();
if (sorter != null)
{
query = await sorter.SortAsync(query, cancellationToken);
}
return await query.ToListAsync(cancellationToken);
}
}
CastWith<T>()
Modern method (v2.0+) for type-safe casting between different types with optimized performance through expression caching. Replaces the traditional Cast() method offering better fluent API, enhanced type safety, and the ability to transform filters, sortings, and objects. Uses FluentCastBuilder to configure mappings.
// Filter casting with CastWith
var entityFilters = dtoFilters.CastWith<Product>(builder => builder
.MapFilter("name", p => p.FullName)
.MapFilter("price", p => p.UnitPrice, value => decimal.Parse(value))
.ExcludeUnmapped());
// Simple object casting
var product = dto.CastWith<Product>(builder => builder
.Map(src => src.Name, dest => dest.FullName)
.Map(src => src.Price, dest => dest.UnitPrice)
.CustomMap(src => src.CategoryName, dest => dest.Category,
name => new Category { Name = name }));
// Sorting casting
var entitySortings = dtoSortings.CastWith<Product>(builder => builder
.MapSorting("created", p => p.CreatedAt)
.MapSorting("name", p => p.DisplayName));
CompositeOperator
Enumerates the composite operators available for combining multiple filter conditions or applying filters to collections. Version 2.1+ introduced the Any and All operators for advanced queries on one-to-many relationships.
// Regular logical operators
CompositeOperator.And // All conditions must be true
CompositeOperator.Or // At least one condition must be true
// Collection operators (v2.1+)
CompositeOperator.Any // Any item in the collection satisfies the conditions
CompositeOperator.All // All items in the collection satisfy the conditions
// Usage example
var adminUsers = new CompositeFiltering<User>(
CompositeOperator.Any, // Any role of the user
u => u.Roles, // In the Roles collection
"Name:eq(Admin)", // That has name equal to Admin
"Name:eq(SuperAdmin)" // OR name equal to SuperAdmin
);
CompositeFiltering<T>
Class that implements composite filters to combine multiple conditions using logical operators (And/Or) and collection operators (Any/All v2.1+). Enables creating complex queries in a type-safe manner with support for string parsing and Entity Framework integration.
// Filter with And operator (all conditions)
var activeProducts = CompositeFiltering.and<Product>(
"IsActive:eq(true)",
"Price:gt(0)",
"Category:neq(Discontinued)"
);
// Filter with Or operator (any condition)
var discountedProducts = CompositeFiltering.or<Product>(
"IsOnSale:eq(true)",
"Price:lt(50)"
);
// Any filter on collections (v2.1+) - users with any admin role
var adminUsers = new CompositeFiltering<User>(
CompositeOperator.Any,
u => u.Roles,
"Name:eq(Admin)",
"Name:eq(Manager)"
);
// All filter on collections (v2.1+) - users with all projects completed
var completedUsers = new CompositeFiltering<User>(
CompositeOperator.All,
u => u.Projects,
"Status:eq(Completed)",
"IsActive:eq(false)"
);
// String query parsing
var parsedFilter = CompositeFiltering.ParseComposite(
"Roles:any(Name:eq(Admin),IsActive:eq(true))"
);
// Application in queries
var users = adminUsers.Filter(dbContext.Users).ToList();
Key Features
Source Generators for Compile-time Code Generation
Automatically generates specifications, filters, and sorting classes at compile time using the GenerateSpecificationsAtt...
Advanced Specification Pattern Implementation
Provides a complete implementation of the Specification Pattern with composite specifications, allowing you to create co...
Entity Filter and Sorter Patterns
Implements sophisticated filtering and sorting patterns that enable clean separation between presentation logic and busi...
Modern CastWith() System - Type-safe Transformation v2.0+
Version 2.0+ introduced a revolutionary casting system with the CastWith() method and FluentCastBuilder. This new system...
Expression Caching v2.0+ - Revolutionary Performance
The expression caching system was completely redesigned in v2.0+ with ConcurrentDictionary usage and .NET 8+ specific op...
Async Support for Modern Applications
Provides full asynchronous support with IAsyncEntityFilter and IAsyncEntitySorter interfaces, enabling non-blocking data...