CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime
5.0.0
dotnet add package CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime --version 5.0.0
NuGet\Install-Package CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime -Version 5.0.0
<PackageReference Include="CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime" Version="5.0.0" />
<PackageVersion Include="CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime" Version="5.0.0" />
<PackageReference Include="CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime" />
paket add CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime --version 5.0.0
#r "nuget: CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime, 5.0.0"
#:package CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime@5.0.0
#addin nuget:?package=CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime&version=5.0.0
#tool nuget:?package=CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime&version=5.0.0
CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime
NodaTime support for the CodoMetis.ValueRanges EF Core plugin: maps the range types of CodoMetis.ValueRanges.NodaTime to PostgreSQL range and multirange columns, bridging through NpgsqlRange<T> via Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime.
| Property type | Column type |
|---|---|
LocalDateRange |
daterange |
RangeSet<LocalDateRange, LocalDate> |
datemultirange |
LocalDateTimeRange |
tsrange |
RangeSet<LocalDateTimeRange, LocalDateTime> |
tsmultirange |
InstantRange |
tstzrange |
RangeSet<InstantRange, Instant> |
tstzmultirange |
YearMonthRange |
daterange (month-aligned) |
RangeSet<YearMonthRange, YearMonth> |
datemultirange (month-aligned) |
Usage
dotnet add package CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime
options.UseNpgsql(connectionString, npgsql => npgsql.UseValueRangesNodaTime());
UseValueRangesNodaTime() implies both UseNodaTime() (the Npgsql NodaTime plugin, which maps the element types LocalDate, LocalDateTime and Instant) and UseValueRanges() (the base plugin) — neither needs to be called separately, and the BCL-based range types keep working in the same model.
The full range algebra translates from LINQ to SQL exactly as documented for the base package — operators (@>, &&, <<, -|-, …), bound accessors (lower, upper, lower_inc, upper_inc), Merge (range_merge), the RangeAgg/RangeIntersectAgg aggregates, Intersect/Union/Except, multirange operations including == equality, and the CreateFinite/CreateUnboundedStart/CreateUnboundedEnd factories as guarded range constructor calls:
var day = new LocalDate(2024, 6, 15);
reservations.Where(r => r.Period.Contains(day)); // r."Period" @> DATE '2024-06-15'
reservations.OrderBy(r => r.Period.LowerBound()); // ORDER BY lower(r."Period")
reservations.Where(r => r.Window.Overlaps(other)); // r."Window" && @other
reservations.GroupBy(r => r.CustomerId)
.Select(g => g.Select(r => r.Period).RangeAgg()); // range_agg(r."Period")
Notes
- No normalization rules. The base package documents
DateTimeKindreinterpretation fortsrangeand UTC offset normalization fortstzrange. Neither applies here:LocalDateTimeis wall-clock time by construction andInstantis an instant by construction — the value written is the value stored. - Discrete canonicalization is compensated exactly as for
DateRange:LocalDateRange.UpperBound()translates toupper(x) - 1, so server results always equal the in-memory results (verified against live PostgreSQL). YearMonthRange(v5) is stored as a month-aligneddaterange:[2025-01, 2025-03]becomes[2025-01-01, 2025-04-01), so no custom database type is needed and every operator works server-side. Bound elements convert through first-of-month dates (Contains(yearMonth)→@> DATE 'yyyy-MM-01');UpperBound()'supper(x) - 1lands on the last day of the end month, which reads back as that month. Reads validate month alignment — a partial-monthdaterangethrows instead of silently shifting. The factories cannot be constructed in SQL from column values (months are coarser than thedatesubtype); constant and parameter ranges work as usual.- Precision: NodaTime carries nanoseconds, PostgreSQL stores microseconds — sub-microsecond precision is reduced at the database boundary.
Instant.MinValue/MaxValuemap to PostgreSQL-infinity/infinityby default (Npgsql rule): a finite bound that happens to be infinite, distinct from an unbounded side (upper_infstaysfalse).- External data sources: when the application builds its own
NpgsqlDataSourceinstead of letting EF create one, callUseNodaTime()on that data source builder as well — the same requirementNpgsql.EntityFrameworkCore.PostgreSQL.NodaTimedocuments. - Store-name lookups: with the Npgsql NodaTime plugin active, resolving a mapping by store type name alone (e.g. scaffolding-style
FindMapping("daterange")) is answered by Npgsql's own plugin (DateInterval). The range types always resolve by CLR type, which is unambiguous. - Reverse engineering (
dotnet ef dbcontext scaffold) does not produce these types — apply them manually after scaffolding, as with the base package.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- CodoMetis.ValueRanges.EFCore.PostgreSQL (>= 5.0.0)
- CodoMetis.ValueRanges.NodaTime (>= 5.0.0)
- Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.