This document provides detailed architectural information for the CmdScale.EntityFrameworkCore.TimescaleDB library.
-
CmdScale.EntityFrameworkCore.TimescaleDB - Core runtime library
- Migrations and SQL generation
- Fluent API and data annotations
- Feature differs and model extractors
-
CmdScale.EntityFrameworkCore.TimescaleDB.Design - Design-time services
- C# code generation for migrations (
dotnet ef migrations add) - Database scaffolding (
dotnet ef dbcontext scaffold) - Registered via MSBuild
.targetsfile withDesignTimeServicesReferenceattribute
- C# code generation for migrations (
- CmdScale.EntityFrameworkCore.TimescaleDB.Tests - Unit tests (xUnit, Moq)
- CmdScale.EntityFrameworkCore.TimescaleDB.FunctionalTests - EF Core specification tests (Testcontainers)
- CmdScale.EntityFrameworkCore.TimescaleDB.Benchmarks - Performance benchmarks (BenchmarkDotNet)
- samples/Eftdb.Samples.Shared/ - Shared models and configurations
- samples/Eftdb.Samples.CodeFirst/ - Code-first migration examples
- samples/Eftdb.Samples.DatabaseFirst/ - Database-first scaffolding examples
| File | Purpose |
|---|---|
TimescaleDbServiceCollectionExtensions.cs |
Registers IMigrationsModelDiffer, IConventionSetPlugin |
TimescaleDbContextOptionsBuilderExtensions.cs |
Service registration via UseTimescaleDb() |
TimescaleDbMigrationsSqlGenerator.cs |
Runtime SQL generator for dotnet ef database update |
When adding new features, follow the same directory structure pattern.
HypertableAttribute.cs- Data annotation:[Hypertable("TimeColumn", ChunkTimeInterval = "1 day")]HypertableConvention.cs- IEntityTypeAddedConvention implementationHypertableAnnotations.cs- Annotation constantsHypertableTypeBuilder.cs- Fluent API:IsHypertable(),WithChunkTimeInterval(), etc.
ReorderPolicyAttribute.cs- Data annotation:[ReorderPolicy("index_name")]ReorderPolicyConvention.cs- IEntityTypeAddedConvention implementationReorderPolicyAnnotations.cs- Annotation constantsReorderPolicyTypeBuilder.cs- Fluent API:WithReorderPolicy()
ContinuousAggregateAttribute.cs- Entity-level attribute defining materialized viewTimeBucketAttribute.cs- Property-level attribute for time bucketingAggregateAttribute.cs- Property-level attribute withEAggregateFunctionenumContinuousAggregateConvention.cs- Processes all three attributes aboveContinuousAggregateAnnotations.cs- 13 annotation constantsContinuousAggregateBuilder<TEntity, TSourceEntity>.cs- Type-safe generic builderContinuousAggregateTypeBuilder.cs- Fluent API extensions
ContinuousAggregatePolicyAttribute.cs- Data annotation:[ContinuousAggregatePolicy]ContinuousAggregatePolicyConvention.cs- IEntityTypeAddedConvention implementationContinuousAggregatePolicyAnnotations.cs- Annotation constantsContinuousAggregatePolicyBuilder.cs- Fluent API builderContinuousAggregateBuilderPolicyExtensions.cs- Extension methods for builder
| File | Purpose |
|---|---|
Dimension.cs |
Represents range/hash partitioning with factory methods |
EDimensionType.cs |
Enum: Range, Hash |
EAggregateFunction.cs |
Enum: Avg, Sum, Min, Max, Count, First, Last |
All inherit MigrationOperation and contain feature-specific properties:
CreateHypertableOperation.cs/AlterHypertableOperation.csAddReorderPolicyOperation.cs/AlterReorderPolicyOperation.cs/DropReorderPolicyOperation.csCreateContinuousAggregateOperation.cs/AlterContinuousAggregateOperation.cs/DropContinuousAggregateOperation.csAddContinuousAggregatePolicyOperation.cs/RemoveContinuousAggregatePolicyOperation.cs
Provides EF.Functions extension methods that translate to TimescaleDB SQL functions at query time.
These are runtime-only — they have no in-memory implementation and throw when called outside LINQ.
| File | Purpose |
|---|---|
TimescaleDbFunctionsExtensions.cs |
Partial class entry point; defines the Throw<T>() helper |
TimescaleDbFunctionsExtensions.TimeBucket.cs |
10 TimeBucket() overloads covering DateTime, DateTimeOffset, DateOnly, int, long |
Internal/TimescaleDbMethodCallTranslatorPlugin.cs |
IMethodCallTranslatorPlugin — registers all translators with EF Core's query pipeline |
Internal/TimescaleDbTimeBucketTranslator.cs |
IMethodCallTranslator — maps each TimeBucket overload to time_bucket(...) SQL |
The plugin is registered in TimescaleDbServiceCollectionExtensions.AddEntityFrameworkTimescaleDb() via .TryAdd<IMethodCallTranslatorPlugin, TimescaleDbMethodCallTranslatorPlugin>().
| File | Purpose |
|---|---|
HypertableOperationGenerator.cs |
Generates create_hypertable(), set_chunk_time_interval(), etc. |
ReorderPolicyOperationGenerator.cs |
Generates add_reorder_policy(), remove_reorder_policy(), etc. |
ContinuousAggregateOperationGenerator.cs |
Generates materialized view SQL |
SqlBuilderHelper.cs |
Quote handling utilities (isDesignTime parameter critical) |
TimescaleMigrationsModelDiffer.cs- Extends EF Core's MigrationsModelDiffer, implementsGetOperationPriority()Features/IFeatureDiffer.cs- Interface:GetDifferences(IRelationalModel? source, IRelationalModel? target)
Feature-specific:
Features/Hypertables/-HypertableDiffer.cs,HypertableModelExtractor.csFeatures/ReorderPolicies/-ReorderPolicyDiffer.cs,ReorderPolicyModelExtractor.csFeatures/ContinuousAggregates/-ContinuousAggregateDiffer.cs,ContinuousAggregateModelExtractor.csFeatures/ContinuousAggregatePolicies/-ContinuousAggregatePolicyDiffer.cs,ContinuousAggregatePolicyModelExtractor.cs
DefaultSchema = "public"
ChunkTimeInterval = "7 days" // ChunkTimeIntervalLong = 604_800_000_000L
ReorderPolicyScheduleInterval = "1 day"
ReorderPolicyMaxRetries = -1 // indefinite
ReorderPolicyMaxRuntime = "00:00:00" // no limit- Configured with
[assembly: DesignTimeProviderServices(...)]attribute - Registers:
ICSharpMigrationOperationGenerator→TimescaleCSharpMigrationOperationGeneratorIDatabaseModelFactory→TimescaleDatabaseModelFactory
- Generates C# code for
dotnet ef migrations add - Calls operation generators with
isDesignTime: true - Outputs
.Sql(@"...")calls in migration Up/Down methods
Orchestrates db-first scaffolding with extractor/applier pairs:
HypertableScaffoldingExtractor+HypertableAnnotationApplierReorderPolicyScaffoldingExtractor+ReorderPolicyAnnotationApplierContinuousAggregateScaffoldingExtractor+ContinuousAggregateAnnotationApplier
Interfaces:
ITimescaleFeatureExtractor.cs-Extract(DbConnection connection)returns feature metadataIAnnotationApplier.cs-ApplyAnnotations(DatabaseTable table, object featureInfo)
Feature Extractors query TimescaleDB system tables:
HypertableScaffoldingExtractor.cs- Queriestimescaledb_information.hypertables, dimensions, chunk statsReorderPolicyScaffoldingExtractor.cs- Queriestimescaledb_information.jobsContinuousAggregateScaffoldingExtractor.cs- Queries continuous aggregate metadata
- MSBuild integration that injects DesignTimeServicesReference attribute
- Generates
GeneratedTimescaleDesignTimeServices.g.csduring compile - Enables
dotnet efCLI tools to discover design-time services
Custom operations are prioritized by TimescaleMigrationsModelDiffer.GetOperationPriority():
| Priority | Operation Type | Reason |
|---|---|---|
| 0 | Standard EF operations | CreateTable, AddColumn, DropColumn, etc. |
| 10 | CreateHypertableOperation |
Tables must exist first |
| 20 | Reorder policy operations | Hypertables must exist |
| 30 | CreateContinuousAggregateOperation |
Source hypertables must exist |
| 40 | Alter/Drop continuous aggregate | Last to ensure dependencies exist |
Continuous aggregates are materialized views that automatically refresh:
- MaterializedViewName: Name of the generated materialized view
- ParentName: Entity name of source hypertable (resolved to table name via EF metadata)
- TimeBucketWidth: Time interval for bucketing (e.g., "1 day", "1 hour")
- TimeBucketSourceColumn: Time column to bucket on (resolved to database column name)
- AggregateFunctions: Colon-delimited strings (see patterns.md)
- GroupByColumns: Column names for GROUP BY
- WhereClause: Raw SQL for filtering (partially implemented)
SQL Generation Special Cases:
first()/last()functions require time ordering column:first(price, timestamp ORDER BY timestamp)time_bucket()function wraps time column in SELECT and GROUP BY- Aggregate column aliases must match property names for EF mapping