Repository navigation
Expression Builders Common
PagedListResult.Common (assembly RzR.ResultMessage.Pagination.Core) translates the DTOs from PagedListResult.DataModels into IQueryable<T> operations. It has no EF Core dependency. You can use it directly against LINQ-to-Objects, against any IQueryable<T> provider, or as the building block of your own custom adapter.
This page describes what the builders do and the public surface you can call. The EF Core integration (EntityFramework Core Extensions) calls these helpers internally; you almost never need to call them yourself.
| Folder | Contents |
|---|---|
Attributes/ |
PaginationDefaultOrderPropertyAttribute, PaginationDefaultTopRecordPrimaryKeyAttribute. |
Extensions/Filters/ |
The four families of expression builders. |
Extensions/Filters/PropertyFilterQuery/ |
Per-condition expression visitors. |
Internal/ |
Reflection caches and helper utilities. |
Helpers/ |
PredefinedRecordsHelper, TimeWatchHelper. |
FilterSourceByTextExpression.FilterSourceByText(...) is invoked by GetPaged* to apply the Search block:
query = query.FilterSourceByText(
request.Search.SearchInAllTextFields,
request.Search.SearchInAllFields,
request.Search.Search,
request.Search.CustomSearchTextProperties,
typeof(TSource));Resolution order for the candidate property set:
-
SearchInAllTextFields == true-> everystringproperty on the entity (default). -
SearchInAllFields == true-> every property on the entity (the builder will useToString()andContainsfor non-string types). - Otherwise -> only the names listed in
CustomSearchTextProperties.
The matching is Contains, case-insensitive. Empty / whitespace search terms are no-ops.
FilterSourceOrderExtensions exposes:
-
OrderByWithDirection(string property, OrderDirection direction, ...)— orders by an explicit property name. The string is matched against the public properties ofTSourceand the direction is applied through the standard LINQ chain. -
OrderByWithDirectionByDefaultProperty(OrderDirection direction, ...)— used whenOrder.OrderByDefaultPropertyistrueand no explicit property was provided. It looks for the first property decorated with[PaginationDefaultOrderProperty]and orders by it.
If none of the above resolves to an actual property, the EF Core extensions fall back to query.OrderBy(x => 0) so that Skip/Take remain deterministic.
public sealed class Product
{
public Guid Id { get; set; }
[PaginationDefaultOrderProperty]
public string Name { get; set; }
public decimal Price { get; set; }
}A request that arrives with Order.OrderByDefaultProperty = true and no explicit OrderByProperty will be ordered by Name.
The filter machinery lives in FilterSourceQueryExtensions and the per-condition visitors under Extensions/Filters/PropertyFilterQuery/.
Two public entry points are used by the EF Core layer:
-
AsSimpleFilterable(IEnumerable<DataFilter> filters)— composes the filters with a top-level AND, ignoringDependencies. Used byGetPagedWithMainFiltersAsync. -
AsFilterable(IEnumerable<DataFilter> filters, FilterConditionType filterLink)— composes the filters with the supplied top-level link (And/Or) and honors each filter'sDependenciescollection. Used byGetPagedWithFiltersAsync.
The per-condition visitors translate FilterType values into Expression<Func<T, bool>> predicates, with appropriate handling of:
- nullable types,
-
stringcomparisons (case-sensitive vs. case-insensitive variants), - numeric,
DateTime,GuidandEnumparsing from the string-encodedValuescollection, -
Between, which needs bothValues[0]andCompareValue, -
IsIn/IsNotIn, which build a typedHashSet<T>and emit aContainscall on it, -
IsNull/IsNotNull, which emit a value-less predicate.
PredefinedRecordsHelper.BuildPredefinedFilter(query, defaultPrimaryKey, predefinedRecord) resolves the property name and the typed identifier collection used to pin a few rows on top of the result. It honours, in order:
-
PredefinedRecord.PredefinedFieldNameif set. - The property decorated with
[PaginationDefaultTopRecordPrimaryKey]ifDefaultPrimaryKeyDefinition.FindByAttribute == true. - The entity's primary key resolved through
DbContext.ModelifFindByEntity == true. - The explicit
DefaultPrimaryKeyDefinition.DefaultPrimaryKeyvalue.
FilterPredefinedTopRecordExtensions exposes the two shaping methods:
-
GetInTopPredefinedRecords(values, propertyNames)— selects the rows whose key is in the set. -
GetNotInTopPredefinedRecords(values, propertyNames)— selects everything else, suitable for the standard paging slice.
The EF Core layer combines both into a single result so that the predefined rows occupy the first slots of page 1 and never bleed into pages 2+.
public sealed class Product
{
[PaginationDefaultTopRecordPrimaryKey]
public Guid Id { get; set; }
public string Name { get; set; }
}When the request omits PredefinedFieldName, this attribute tells the builder to match identifiers against Id.
ReflectionTypeStorage and the helpers under Internal/ cache PropertyInfo lookups by (type, property name). The cost of building each predicate is therefore dominated by the expression construction itself (a constant overhead), not by reflection. The caches are static and thread-safe.
- You want pagination over an in-memory collection (
IEnumerable<T>is converted toIQueryable<T>viaAsQueryable()). - You want to call the filter builder against a non-EF Core provider (Cosmos, Marten, NHibernate, custom LINQ provider).
- You want to compose predicates and apply them yourself instead of going through
GetPaged*.
For everything else, prefer the higher-level PagedListResult package.
PagedListResult is maintained by RzR. GitHub repository.
Start here
Reference
- Data Models Reference
- Expression Builders (Common)
- EntityFramework Core Extensions
- Query String Syntax
ASP.NET Core integration
- Web Integration Overview
- MVC Integration
- Minimal API Integration
- Configuration and Options
- Allow List Registry
- Response Headers and ProblemDetails
- OpenAPI and ApiExplorer
Operations