PredicateMapper 0.1.4
dotnet add package PredicateMapper --version 0.1.4
NuGet\Install-Package PredicateMapper -Version 0.1.4
<PackageReference Include="PredicateMapper" Version="0.1.4" />
<PackageVersion Include="PredicateMapper" Version="0.1.4" />
<PackageReference Include="PredicateMapper" />
paket add PredicateMapper --version 0.1.4
#r "nuget: PredicateMapper, 0.1.4"
#:package PredicateMapper@0.1.4
#addin nuget:?package=PredicateMapper&version=0.1.4
#tool nuget:?package=PredicateMapper&version=0.1.4
Expression Mapping Library
A lightweight library for rewriting Expression<Func<TDestination, bool>> predicates into Expression<Func<TSource, bool>> predicates. Generates SQL-translatable expressions for use where you want to expose generic higher-order functions without leaking your internal persistence model.
Quick Start
Define a mapper for each source/destination pair by subclassing EntityMapper<TSource, TDestination> and implementing Configure():
public class UserMapper : EntityMapper<UserEntity, UserDto>
{
protected override void Configure()
{
Map(src => src.UserId, dst => dst.Id);
Map(src => src.FullName, dst => dst.Name);
Map(src => src.IsEnabled, dst => dst.IsActive);
}
}
Use it in your repository:
public IEnumerable<UserDto> Find(Expression<Func<UserDto, bool>> predicate)
{
var mapper = new UserMapper();
var mappedPredicate = mapper.Map(predicate);
return _dbSet.Where(mappedPredicate).Select(src => MapToDto(src));
}
Nested Mappers
When a property is itself a mapped type, pass a mapper instance for the nested type:
public class UserMapper : EntityMapper<UserEntity, UserDto>
{
protected override void Configure()
{
Map(src => src.UserId, dst => dst.Id);
Map(src => src.FullName, dst => dst.Name);
Map(src => src.Address, dst => dst.Address, new AddressMapper());
Map(src => src.OrderEntities, dst => dst.Orders, new OrderMapper());
}
}
For self-referential types, pass a factory to defer construction:
public class CategoryMapper : EntityMapper<CategoryEntity, CategoryDto>
{
protected override void Configure()
{
Map(src => src.Id, dst => dst.Id);
Map(src => src.Name, dst => dst.Name);
Map(src => src.Children, dst => dst.Children, () => this);
}
}
Supported Predicate Patterns
These are the expression node types the library rewrites. All are verified to produce valid SQL via EF Core.
| Pattern | Example |
|---|---|
| Member access equality | dst.Id == id |
| Comparison operators | dst.Age > 18 |
Boolean binary (&&, \|\|) |
dst.IsActive && dst.Age > 18 |
| Unary negation | !dst.IsActive |
| Null checks | dst.Address != null |
| Navigation property chaining | dst.Address.City == "London" |
| String methods | dst.Name.StartsWith("A") |
Collection: Any |
dst.Orders.Any(o => o.Total > 100) |
Collection: All |
dst.Orders.All(o => o.IsPaid) |
Collection: Contains |
dst.Tags.Contains("vip") |
| Captured primitive closures | dst.Id == capturedVar |
Validation
All destination members must be mapped. The library validates this at construction time — misconfigured mappers throw InvalidMappingException before any predicate is ever rewritten:
// Throws InvalidMappingException: unmapped destination members: Name, IsActive
public class IncompleteMapper : EntityMapper<UserEntity, UserDto>
{
protected override void Configure()
{
Map(src => src.UserId, dst => dst.Id);
// Name and IsActive not mapped — caught immediately on instantiation
}
}
Unmapped source members are safe to omit — they will never appear in a destination expression.
Known Limitations
- Method calls beyond
Any,All,Contains, and the string methodsStartsWith,EndsWith,Containsare not rewritten and will throwUnsupportedExpressionExceptionat map time - Composite source expressions (e.g. mapping
src.First + " " + src.Lasttodst.FullName) are not supported in v1 — both sides of a mapping must be simple member access - Closures over complex captured objects should be tested against your ORM — captured primitives and local collections are handled correctly
How It Fits Into The Repository Pattern
This library sits inside repository implementations, invisible to consumers. The service layer works exclusively with DTO expressions. The repository is the only location that knows a persistence model exists.
Service Layer → Expression<Func<UserDto, bool>>
Repository → EntityMapper rewrites to Expression<Func<UserEntity, bool>>
ORM / Database → SQL
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.