{"id":30622233,"url":"https://github.com/cmdscale/cmdscale.entityframeworkcore.timescaledb","last_synced_at":"2026-02-25T12:28:39.066Z","repository":{"id":311723731,"uuid":"1044406987","full_name":"cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB","owner":"cmdscale","description":"Extension of Npgsql.EntityFrameworkCore.PostgreSQL to add support for TimescaleDB.","archived":false,"fork":false,"pushed_at":"2026-02-11T01:26:23.000Z","size":548,"stargazers_count":46,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-11T01:41:16.933Z","etag":null,"topics":["csharp","dotnet","efcore","hypertable","timescaledb"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmdscale.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-25T16:27:22.000Z","updated_at":"2026-02-11T01:21:12.000Z","dependencies_parsed_at":"2025-12-15T21:19:33.978Z","dependency_job_id":null,"html_url":"https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB","commit_stats":null,"previous_names":["cmdscale/cmdscale.entityframeworkcore.timescaledb"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdscale%2FCmdScale.EntityFrameworkCore.TimescaleDB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdscale%2FCmdScale.EntityFrameworkCore.TimescaleDB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdscale%2FCmdScale.EntityFrameworkCore.TimescaleDB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdscale%2FCmdScale.EntityFrameworkCore.TimescaleDB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmdscale","download_url":"https://codeload.github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdscale%2FCmdScale.EntityFrameworkCore.TimescaleDB/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29819265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T05:36:42.804Z","status":"ssl_error","status_checked_at":"2026-02-25T05:36:31.934Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","efcore","hypertable","timescaledb"],"created_at":"2025-08-30T15:32:17.450Z","updated_at":"2026-02-25T12:28:39.061Z","avatar_url":"https://github.com/cmdscale.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# CmdScale.EntityFrameworkCore.TimescaleDB\n\n![CmdScale Project](https://github.com/cmdscale/.github/raw/main/profile/assets/CmdShield.svg)\n[![Test Workflow](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/actions/workflows/run-tests.yml/badge.svg)](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/actions/workflows/run-tests.yml)\n[![NuGet downloads](https://img.shields.io/nuget/dt/CmdScale.EntityFrameworkCore.TimescaleDB?logo=nuget\u0026label=Downloads)](https://www.nuget.org/packages/CmdScale.EntityFrameworkCore.TimescaleDB)\n[![codecov](https://codecov.io/gh/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/graph/badge.svg?token=YP3YCJLQ41)](https://codecov.io/gh/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB)\n[![GitHub release (latest by date)](https://img.shields.io/github/v/tag/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB)](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/tags)\n[![GitHub issues](https://img.shields.io/github/issues/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB)](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/issues)\n[![GitHub license](https://img.shields.io/github/license/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB)](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/blob/main/LICENSE)\n![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThis repository provides the essential libraries and tooling to seamlessly integrate [TimescaleDB](https://www.timescale.com/), the leading open-source time-series database, with Entity Framework Core. It is designed to give you the full power of TimescaleDB's features, like hypertables and compression, directly within the familiar EF Core environment.\n\n- **CmdScale.EntityFrameworkCore.TimescaleDB**: The core runtime library. You include this in your project to enable TimescaleDB-specific features when configuring your `DbContext`.\n- **CmdScale.EntityFrameworkCore.TimescaleDB.Design**: Provides crucial design-time extensions. This package enhances the EF Core CLI tools (`dotnet ef`) to understand TimescaleDB concepts, enabling correct schema generation for migrations and scaffolding.\n\n\u003e [!TIP]\n\u003e Learn more about **Eftdb** in the [documentation](https://eftdb.cmdscale.com/docs/).\n\n\u003e [!NOTE]\n\u003e While AI tools like Copilot or Claude are permitted, vibe-coded submissions will be rejected. All code must be manually verified and subject to the standard code review process.\n\n---\n\n## ✨ Features\n\nThis package extends **Entity Framework Core** with powerful, first-class support for **TimescaleDB's** core features, allowing you to build high-performance time-series applications in .NET.\n\n### Hypertable Creation and Configuration\n\nSeamlessly define and manage **TimescaleDB hypertables** using standard EF Core conventions, including both data attributes and a rich **Fluent API**. This allows you to control partitioning and other optimizations directly from your `DbContext`.\n\n- **Time Partitioning**: Easily specify the primary time column and set the `chunk_time_interval`.\n- **Space Partitioning**: Add additional dimensions for hash or range partitioning to further optimize queries.\n- **Chunk Time Interval**: Configure chunk intervals to balance performance and storage efficiency.\n- **Data Migration**: Control whether existing data should be migrated when converting a regular table to a hypertable using `migrate_data`.\n- **Chunk Skipping**: Enable chunk skipping to improve query performance on specific columns.\n- **Compression Segment By**: Define columns to group compressed data by, allowing efficient access to specific segments without decompressing entire chunks.\n- **Compression Order By**: Specify the sort order within compressed segments, with support for ascending/descending direction and NULLS FIRST/LAST positioning.\n\n### Reorder Policies\n\nTake full control over how your hypertable data is organized on disk with **TimescaleDB's** reorder policies. By defining a reorder policy, you can automatically re-sort chunks of data by a specified index, significantly improving the performance of queries that scan large time ranges or specific index values.\n\n### Continuous Aggregates\n\nCreate and manage **TimescaleDB continuous aggregates** — automatically refreshed materialized views that pre-compute aggregate data for faster queries. Define time-bucketed aggregations using a type-safe Fluent API or Data Annotations.\n\n- **Time Bucketing**: Automatically group data into time intervals (e.g., `1 hour`, `1 day`).\n- **Aggregate Functions**: Support for `Avg`, `Sum`, `Min`, `Max`, `Count`, `First`, and `Last`.\n- **Group By Columns**: Add additional grouping dimensions beyond time.\n- **Filtering**: Apply WHERE clauses to filter source data.\n- **Refresh Policies**: Configure automatic refresh with customizable time windows, schedule intervals, and batching options.\n\n---\n\n## 📦 NuGet Packages\n\nTo get started, install the necessary packages from NuGet. For a typical project, you will need both.\n\n| Package                                           | Description                               |\n| ------------------------------------------------- | ----------------------------------------- |\n| `CmdScale.EntityFrameworkCore.TimescaleDB`        | Runtime support for EF Core + TimescaleDB |\n| `CmdScale.EntityFrameworkCore.TimescaleDB.Design` | Design-time support for EF Core tooling   |\n\n---\n\n## 🧰 Setup\n\nTo enable TimescaleDB in your project, chain the `.UseTimescaleDb()` method after `.UseNpgsql()` when configuring your DbContext. This call registers all the necessary components to make EF Core aware of TimescaleDB's unique features.\nNote that you do **NOT** have to install `Npgsql.EntityFrameworkCore.PostgreSQL` as it is referenced transitively via `CmdScale.EntityFrameworkCore.TimescaleDB`.\n\nIn `Program.cs` or your dependency injection container:\n\n```csharp\nstring? connectionString = builder.Configuration.GetConnectionString(\"Timescale\");\n\nbuilder.Services.AddDbContext\u003cTimescaleContext\u003e(options =\u003e\n    options.UseNpgsql(connectionString).UseTimescaleDb());\n```\n\n---\n\n## 🔧 Fluent API Example\n\nThe Fluent API provides a powerful, type-safe way to configure your entities. Use the `.IsHypertable()` extension method on an entity builder to designate it as a hypertable and configure its properties.\n\n### Model\n\nA standard POCO class representing our time-series data.\n\n```csharp\npublic class WeatherData\n{\n    public Guid Id { get; set; }\n    public DateTime Time { get; set; }\n    public double Temperature { get; set; }\n    public double Humidity { get; set; }\n}\n```\n\n### Configuration\n\nIn a separate configuration class, you can define the hypertable settings.\n\n```csharp\npublic class WeatherDataConfiguration : IEntityTypeConfiguration\u003cWeatherData\u003e\n{\n    public void Configure(EntityTypeBuilder\u003cWeatherData\u003e builder)\n    {\n        // Define a composite primary key, common for time-series data.\n        builder.HasKey(x =\u003e new { x.Id, x.Time });\n\n        // Convert the table to a hypertable partitioned on the 'Time' column.\n        builder.IsHypertable(x =\u003e x.Time)\n               // Optional: Enable chunk skipping for faster queries on this column.\n               .WithChunkSkipping(x =\u003e x.Time)\n               // Optional: Set the chunk interval. Can be a string (\"7 days\") or long (microseconds).\n               .WithChunkTimeInterval(\"86400000\")\n               // Optional: Migrate existing data when converting to hypertable (defaults to false).\n               .WithMigrateData(true);\n    }\n}\n```\n\n---\n\n## 🏷️ Data Annotations Example\n\nFor simpler configurations, you can use the [Hypertable] attribute directly on your model class.\n\n```csharp\n[Hypertable(nameof(Time),\n    ChunkSkipColumns = new[] { \"Time\" },\n    ChunkTimeInterval = \"86400000\",\n    MigrateData = true)]\n[PrimaryKey(nameof(Id), nameof(Time))]\npublic class DeviceReading\n{\n    public Guid Id { get; set; }\n    public DateTime Time { get; set; }\n    public string DeviceId { get; set; } = string.Empty;\n    public double Voltage { get; set; }\n    public double Power { get; set; }\n}\n```\n\n---\n\n## 🐳 Docker Support\n\nFor convenient local development, a `docker-compose.yml` file is included in the **Solution Items**. This allows you to spin up a pre-configured TimescaleDB instance with a single command.\n\n### Start TimescaleDB container\n\nFrom the solution root, run:\n\n```bash\ndocker-compose up -d\n```\n\n### Resetting the Database Environment\n\nIf you need to start with a completely fresh, empty database, you can stop the running container and permanently delete all of its data.\n\n\u003e **Warning**: This command is destructive and will erase all tables and data stored in your local TimescaleDB instance.\n\n```bash\ndocker-compose down -v\n```\n\n---\n\n## 🧪 Testing\n\nThis project uses a two-tier testing strategy to ensure code quality and correctness.\n\n\u003e Checkout the test coverage on [Codecov](https://app.codecov.io/gh/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB)\n\n### Test Projects\n\n| Project                                                    | Purpose                                                                                                                                                          |\n| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `CmdScale.EntityFrameworkCore.TimescaleDB.Tests`           | Unit tests using xUnit and Moq. Fast, isolated tests for differs, extractors, generators, and conventions. Also includes integration tests using Testcontainers. |\n| `CmdScale.EntityFrameworkCore.TimescaleDB.FunctionalTests` | EF Core specification tests validating end-to-end behavior against a real TimescaleDB instance.                                                                  |\n\n### Running Tests\n\n```bash\n# Run all tests\ndotnet test\n\n# Run a specific test by name\ndotnet test --filter \"FullyQualifiedName~HypertableDifferTests\"\n```\n\n### Test Coverage\n\nGenerate an HTML coverage report using [ReportGenerator](https://github.com/danielpalme/ReportGenerator):\n\n```bash\n# Install ReportGenerator (once)\ndotnet tool install -g dotnet-reportgenerator-globaltool\n\n# Run tests with coverage collection\ndotnet test tests/Eftdb.Tests --settings tests/Eftdb.Tests/coverlet.runsettings --collect:\"XPlat Code Coverage\"\n\n# Generate HTML report from coverage files\nreportgenerator -reports:\"tests/Eftdb.Tests/TestResults/**/coverage.cobertura.xml\" -targetdir:\"tests/Eftdb.Tests/TestResults/CoverageReport\" -reporttypes:Html\n```\n\nThe HTML report will be generated at `tests/Eftdb.Tests/TestResults/CoverageReport/index.html`.\n\n### Mutation Testing\n\nUse [Stryker.NET](https://stryker-mutator.io/docs/stryker-net/introduction) to validate test effectiveness by introducing mutations and checking if tests catch them:\n\n```bash\n# Install Stryker (once)\ndotnet tool install -g dotnet-stryker\n\n# Run from the test directory\ncd tests/Eftdb.Tests\ndotnet stryker\n\n# Quick run (test only changed files)\ndotnet stryker --since\n```\n\nResults are generated in `StrykerOutput/reports/mutation-report.html`. See `STRYKER_README.md` in the `CmdScale.EntityFrameworkCore.TimescaleDB.Tests` project for detailed configuration.\n\n---\n\n## 🛠️ Scripts\n\nThis repository includes PowerShell scripts to streamline the development workflow, particularly for switching between local project development and package-based testing.\n\n### Allow PowerShell Scripts to Run\n\nTo run these scripts, you may first need to change the execution policy for the current process:\n\n```powershell\nSet-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process\n```\n\n### Switch Project/Package References\n\nThese script modify your `.csproj` files to switch between referencing the core libraries as direct project or as local NuGet packages.\n\nSwitch to **project references** (ideal for active development):\n\n```powershell\n.\\scripts\\Switch-References.ps1 -Mode Project\n```\n\nSwitch to **NuGet package references** (to simulate a real-world consumer):\n\n```powershell\n.\\scripts\\Switch-References.ps1 -Mode Package\n```\n\n---\n\n## 📦 Publish Local NuGet Package\n\nTo build and publish the core libraries to a local NuGet feed for testing, use the central publishing script. Note that this also done automatically by the `.\\SwitchToPackageReferences.ps1` script.\n\n```powershell\n# Publish the design-time package\n.\\scripts\\Publish-Local.ps1 -ProjectName \"Eftdb.Design\"\n\n# Publish the runtime package\n.\\scripts\\Publish-Local.ps1 -ProjectName \"Eftdb\"\n```\n\n\u003e To change this path, edit the `$LocalNuGetRepo` variable inside the `Publish-Local.ps1` script.\n\n---\n\n## 🔗 Add Local NuGet Source (Optional)\n\nTo use the locally published NuGet packages in other projects, you need to tell NuGet where to find them.\n\nAdd the local folder as a NuGet source using the .NET CLI:\n\n```bash\ndotnet nuget add source \"path\\NuGet-Packages\" --name LocalCmdScale\n```\n\nOr, configure it in Visual Studio:\n\n1. Go to `Tools` → `NuGet Package Manager` → `Package Manager Settings`.\n2. Navigate to the `Package Sources` section.\n3. Click the '+' icon to add a new source, give it a name (e.g., \"LocalCmdScale\"), and set the path to your local feed folder.\n\n## 🔖 Release strategy\n\nEftdb targets the latest .NET LTS release. Support follows a rolling two-version model:\n\n| Support Level    | Scope                      |\n| ---------------- | -------------------------- |\n| **Current LTS**  | New features and bug fixes |\n| **Previous LTS** | Critical bug fixes only    |\n\n**Example:** When .NET 12 (LTS) releases, it becomes the development target. .NET 10 receives only critical fixes, and .NET 8 support ends.\n\nThis policy balances maintainability with ensuring the most widely-used .NET versions receive support.\n\n## 📚 Resources\n\n- [TimescaleDB Documentation](https://docs.timescale.com/)\n- [Entity Framework Core Documentation](https://learn.microsoft.com/en-us/ef/core/)\n\n---\n\n## Contributing 🤝\n\nWe welcome contributions to help improve this package and make it even more powerful for the .NET and TimescaleDB communities!\n\nWhether you're fixing bugs, adding new features, improving documentation, or sharing examples — every bit helps. 🙌\n\n### How to Contribute\n\n1. **Fork the Repository**\n\n   Create a personal fork of the repository on GitHub and clone it to your local machine.\n\n2. **Create a Branch**\n\n   Use a descriptive branch name based on the feature or fix you're working on using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/):\n\n   ```bash\n   git checkout -b feature/improve-bulk-copy\n   git checkout -b fix/bulk-copy-complex-type-bug\n   ```\n\n3. **Make Your Changes**\n\n   - Follow the existing code style and patterns.\n   - Write meaningful tests for any new logic. Check out the [Wiki](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/wiki) to gain knowledge about writing tests.\n\n4. **Run Tests**\n\n   Make sure all tests pass before submitting a pull request:\n\n   ```bash\n   dotnet test\n   ```\n\n5. **Submit a Pull Request**\n\n   Push your branch and open a pull request (PR) and include a clear description of what you changed and why.\n\n### Guidelines\n\n- Keep pull requests focused and minimal.\n- Reference any related issues using keywords (e.g. `Fixes #42`).\n- Be respectful in code reviews and discussions.\n- Use [BenchmarkDotNet](https://benchmarkdotnet.org/) where performance-related changes are involved.\n\n### AI Assistants\n\nContributors are allowed to use AI assistants such as Claude Code, GitHub Copilot, or similar tools. However, AI-generated code must not be submitted blindly. Contributors are responsible for every line of code in their pull requests. Code quality is very important and AI-assisted contributions are held to the same standard as any other.\n\nBefore submitting AI-assisted contributions, make sure to:\n\n- **Review all generated code** for correctness, readability, and security.\n- **Verify that tests pass** and add new tests where appropriate and effective.\n- **Follow the project's coding style and conventions** — don't let your AI assistant overuse comments; code should be self-explanatory, and comments should explain *why*, not *what*.\n\nThis repository ships with a [Claude Code](https://claude.ai/code) setup in the `.claude/` directory, including specialized agents, coding rules, reusable skills, and architecture reference docs. Personal settings go in `.claude/settings.local.json` (gitignored).\n\n\n### Questions or Ideas?\n\nIf you have questions, ideas, or need help getting started, feel free to [open an issue](https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB/issues). We’re happy to help and discuss!\n\nThank you for contributing! 💜\n\n---\n\n## 📄 License\n\n```txt\nMIT License\nCopyright (c) 2025 CmdScale GmbH\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdscale%2Fcmdscale.entityframeworkcore.timescaledb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmdscale%2Fcmdscale.entityframeworkcore.timescaledb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdscale%2Fcmdscale.entityframeworkcore.timescaledb/lists"}