Built-in profiles per primitive type¶
What this does¶
When [Map] does not specify Profile = typeof(...), the generator's ProfileResolver picks a built-in profile by the property's declared CLR type. Each built-in profile ships a fixed operator set tailored to that type — string substring matching, numeric comparisons, temporal range checks, etc.
When to use¶
Always, unless you have a reason to opt out. Letting the resolver pick is the lowest-friction path: you declare [Map(nameof(User.Age))] on an int property and get eq, gt, lt, in, between, and friends for free. Reach for Profile = typeof(MyProfile) only when you need operators the built-in does not provide, or when multiple profiles match the same CLR type and you must disambiguate.
CLR type mapping¶
| CLR type | Profile | Operators |
|---|---|---|
string |
StringFilter |
eq, ne, contains, startsWith, endsWith, in, isNull |
int, long, short, byte, sbyte, ushort, uint, ulong |
Numeric/Int32Filter, Int64Filter, etc. |
eq, ne, gt, gte, lt, lte, in, isNull |
decimal, double, float |
DecimalFilter, DoubleFilter, SingleFilter |
eq, ne, gt, gte, lt, lte, in, isNull |
bool |
BoolFilter |
eq, isNull |
Guid |
GuidFilter |
eq, ne, in, isNull |
DateTime |
DateTimeFilter |
eq, ne, gt, gte, lt, lte, isNull |
DateTimeOffset |
Temporal/DateTimeOffsetFilter |
eq, ne, gt, gte, lt, lte, isNull |
DateOnly |
Temporal/DateOnlyFilter |
eq, ne, gt, gte, lt, lte, isNull |
TimeOnly |
Temporal/TimeOnlyFilter |
eq, ne, gt, gte, lt, lte, isNull |
any enum |
auto-emitted <EnumName>Filter |
eq, ne, in, isNull |
Nullable reference and value-typed columns share the underlying type's profile — string? resolves to StringFilter, int? resolves to Int32Filter. The isNull operator uses the nullable form internally.
Variations¶
- Override per-property —
[Map(nameof(User.Name), Profile = typeof(StringFilterPlus))]opts that property into a custom profile. Useful when most string columns want the built-in surface but a few need extras. - Auto-emitted enum profiles — every enum referenced in the entity graph picks up an auto-generated
<EnumName>Filterprofile. You don't need to declare anything; the resolver finds it.
Pitfalls¶
- Declaring any custom
[FilterProfile<T>]for a CLR type that already has a built-in makes resolution ambiguous and firesFN0014. From that point forward, every[Map]for properties of that type must specifyProfile = typeof(...)explicitly. The sample app'sStringFilterPlusis exactly this case — adding it forces every[Map]on astringcolumn to name a profile. - Mapping a property whose CLR type has no built-in match (a custom struct, a third-party value type) without
Profile = typeof(...)raisesFN0008. Either declare a custom profile for the type or specify one on the map.