EF.CH 8.0.7

dotnet add package EF.CH --version 8.0.7
                    
NuGet\Install-Package EF.CH -Version 8.0.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EF.CH" Version="8.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EF.CH" Version="8.0.7" />
                    
Directory.Packages.props
<PackageReference Include="EF.CH" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EF.CH --version 8.0.7
                    
#r "nuget: EF.CH, 8.0.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EF.CH@8.0.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EF.CH&version=8.0.7
                    
Install as a Cake Addin
#tool nuget:?package=EF.CH&version=8.0.7
                    
Install as a Cake Tool

EF.CH - Entity Framework Core Provider for ClickHouse

An Entity Framework Core provider for ClickHouse, built on the ClickHouse.Driver ADO.NET driver.

Features

  • LINQ to ClickHouse SQL - Full query translation with ClickHouse-specific optimizations
  • MergeTree Engine Family - MergeTree, ReplacingMergeTree, SummingMergeTree, AggregatingMergeTree, CollapsingMergeTree
  • Rich Type System - Arrays, Maps, Tuples, Nested types, Enums, IPv4/IPv6, DateTime64
  • Materialized Views - LINQ-based and raw SQL definitions
  • Projections - Pre-sorted and pre-aggregated table-level optimizations
  • EF Core Migrations - DDL generation with ClickHouse-specific clauses
  • DELETE Support - Lightweight and mutation-based strategies
  • Dictionaries - In-memory key-value stores with dictGet translation
  • External Entities - Query PostgreSQL, MySQL, Redis, and ODBC sources via table functions
  • Scaffolding - Reverse engineering with C# enum generation
  • Compression Codecs - Per-column compression via fluent API and attributes
  • Window Functions - Row numbering, ranking, lag/lead, running totals with fluent API
  • Data Skipping Indices - Minmax, bloom filter, token/ngram bloom filters, and set indices
  • Time Series Gap Filling - WITH FILL and INTERPOLATE for continuous time series data
  • Query Modifiers - FINAL, SAMPLE, PREWHERE, and SETTINGS for query-level hints
  • Computed Columns - MATERIALIZED, ALIAS, and DEFAULT expression columns
  • Aggregate Combinators - State, Merge, If, and Array combinators for AggregatingMergeTree
  • Native JSON Type - ClickHouse 24.8+ subcolumn access with extension method API

Quick Start

// 1. Install the package
// dotnet add package EF.CH

// 2. Create your entity
public class Order
{
    public Guid Id { get; set; }
    public DateTime OrderDate { get; set; }
    public string CustomerId { get; set; } = string.Empty;
    public decimal Total { get; set; }
}

// 3. Create your DbContext
public class MyDbContext : DbContext
{
    public DbSet<Order> Orders => Set<Order>();

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseClickHouse("Host=localhost;Database=mydb");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.UseMergeTree(x => new { x.OrderDate, x.Id });  // Required: ORDER BY
            entity.HasPartitionByMonth(x => x.OrderDate);         // Optional: partitioning
        });
    }
}

// 4. Use it
await using var context = new MyDbContext();
await context.Database.EnsureCreatedAsync();

context.Orders.Add(new Order
{
    Id = Guid.NewGuid(),
    OrderDate = DateTime.UtcNow,
    CustomerId = "customer-123",
    Total = 99.99m
});
await context.SaveChangesAsync();

var recentOrders = await context.Orders
    .Where(o => o.OrderDate > DateTime.UtcNow.AddDays(-7))
    .ToListAsync();

Installation

dotnet add package EF.CH

Requirements:

  • .NET 8.0+
  • ClickHouse 22.0+
  • EF Core 8.0+

ClickHouse Concepts for EF Core Developers

If you're coming from SQL Server or PostgreSQL, ClickHouse works differently. Understanding these differences is essential:

Every Table Needs an ENGINE

Unlike SQL Server where tables "just work", ClickHouse requires you to specify a table engine. The MergeTree family is most common:

// This is REQUIRED - there's no default engine
entity.UseMergeTree(x => new { x.OrderDate, x.Id });

No ACID Transactions

ClickHouse uses eventual consistency. SaveChanges() batches INSERTs but there's no rollback on failure. Design your application accordingly.

No Row-Level UPDATE

ClickHouse doesn't support efficient UPDATE statements. Attempting to update an entity throws NotSupportedException. Instead:

  • Use ReplacingMergeTree with a version column for "last write wins" semantics
  • Use delete-and-reinsert patterns for infrequent updates

Batch-Oriented, Not Row-at-a-Time

ClickHouse is optimized for bulk inserts (thousands of rows). Single-row inserts work but aren't efficient. Batch your writes when possible.

No Auto-Increment

There's no IDENTITY or auto-increment. Use Guid or application-generated IDs:

public Guid Id { get; set; } = Guid.NewGuid();

No Foreign Key Enforcement

ClickHouse doesn't enforce referential integrity. Foreign keys are your application's responsibility.

Table Engines

Choose the right engine for your use case:

Engine Use Case Configuration
MergeTree General purpose, append-only entity.UseMergeTree(x => x.Id)
ReplacingMergeTree Deduplication by key with version entity.UseReplacingMergeTree(x => x.Version, x => x.Id)
SummingMergeTree Auto-sum numeric columns entity.UseSummingMergeTree(x => new { x.Date, x.ProductId })
AggregatingMergeTree Pre-aggregated state entity.UseAggregatingMergeTree(x => x.Key)
CollapsingMergeTree Row cancellation with sign entity.UseCollapsingMergeTree(x => x.Sign, x => x.Key)
VersionedCollapsingMergeTree Out-of-order row cancellation entity.UseVersionedCollapsingMergeTree(x => x.Sign, x => x.Version, x => x.Key)

See docs/engines/ for detailed documentation on each engine.

Type Mappings

.NET Type ClickHouse Type
int, long, short, sbyte Int32, Int64, Int16, Int8
uint, ulong, ushort, byte UInt32, UInt64, UInt16, UInt8
float, double Float32, Float64
decimal Decimal(18, 4)
string String
bool Bool
Guid UUID
DateTime DateTime64(3)
DateTimeOffset DateTime64(3) with timezone
DateOnly Date
TimeOnly Time
T[], List<T> Array(T)
Dictionary<K,V> Map(K, V)
enum Enum8 or Enum16 (auto-selected)
JsonElement, JsonDocument JSON
T (POCO class) JSON (via value converter)

See docs/types/ for the complete type mapping reference.

Key Differences from SQL Server/PostgreSQL

Feature SQL Server/PostgreSQL ClickHouse
Transactions Full ACID Eventual consistency
UPDATE Efficient row updates Not supported - use ReplacingMergeTree
DELETE Immediate Lightweight (marks) or mutation (async rewrite)
Auto-increment IDENTITY, SERIAL Not available - use UUID
Foreign Keys Enforced constraints Application-level only
Indexes B-tree, hash, etc. Primary key (ORDER BY) + skip indices
Insert Pattern Row-at-a-time OK Batch thousands of rows
Use Case OLTP OLAP/Analytics

Table Options

// Partitioning - improves query performance and data management
entity.HasPartitionByMonth(x => x.CreatedAt);  // PARTITION BY toYYYYMM()
entity.HasPartitionByDay(x => x.EventDate);    // PARTITION BY toYYYYMMDD()

// TTL - automatic data expiration
entity.HasTtl("CreatedAt + INTERVAL 90 DAY");

// Sampling - for approximate queries on large datasets
entity.HasSampleBy("intHash32(UserId)");

Computed Columns

ClickHouse supports three types of computed columns:

public class Order
{
    public Guid Id { get; set; }
    public decimal Amount { get; set; }
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;

    // MATERIALIZED - computed on INSERT, stored on disk
    [MaterializedColumn("Amount * 1.1")]
    public decimal TotalWithTax { get; set; }

    // ALIAS - computed at query time, not stored
    [AliasColumn("concat(FirstName, ' ', LastName)")]
    public string FullName { get; set; } = string.Empty;

    // DEFAULT expression - computed if no value provided
    [DefaultExpression("now()")]
    public DateTime CreatedAt { get; set; }
}

// Or via fluent API
modelBuilder.Entity<Order>(entity =>
{
    entity.Property(e => e.TotalWithTax).HasMaterializedExpression("Amount * 1.1");
    entity.Property(e => e.FullName).HasAliasExpression("concat(FirstName, ' ', LastName)");
    entity.Property(e => e.CreatedAt).HasDefaultExpression("now()");
});
Type Storage Performance Use Case
MATERIALIZED Stored on disk Fast reads Derived values needed frequently
ALIAS Not stored Computed each query Virtual columns, rarely used
DEFAULT Stored when provided Normal Auto-generated values like timestamps

Note: MATERIALIZED columns are excluded from SELECT * by default. Use explicit column selection to read them.

See docs/features/computed-columns.md for full documentation.

Query Modifiers

ClickHouse-specific query hints via LINQ extension methods:

using EF.CH.Extensions;

// FINAL - force deduplication for ReplacingMergeTree
var users = await context.Users
    .Final()
    .ToListAsync();

// SAMPLE - probabilistic sampling (~10% of rows)
var sample = await context.Events
    .Sample(0.1)
    .ToListAsync();

// PREWHERE - optimized pre-filtering (reads filter columns first)
var filtered = await context.Events
    .PreWhere(e => e.Date > cutoffDate)
    .ToListAsync();

// SETTINGS - query-level execution hints
var events = await context.Events
    .WithSetting("max_threads", 4)
    .ToListAsync();

When to use PREWHERE:

  • Filter on indexed/sorted columns (ORDER BY key columns)
  • Highly selective filters that eliminate most rows
  • Large tables where I/O reduction matters

See docs/features/query-modifiers.md for full documentation.

DELETE Operations

// Via change tracker (lightweight delete by default)
var entity = await context.Orders.FindAsync(id);
context.Orders.Remove(entity);
await context.SaveChangesAsync();

// Bulk delete
await context.Orders
    .Where(o => o.OrderDate < cutoffDate)
    .ExecuteDeleteAsync();

// Configure mutation-based delete
options.UseClickHouse("...", o => o.UseDeleteStrategy(ClickHouseDeleteStrategy.Mutation));

Window Functions

using EF.CH.Extensions;

var analytics = context.Orders.Select(o => new
{
    o.Id,
    // Lambda style (recommended) - no .Value needed
    RowNum = Window.RowNumber(w => w
        .PartitionBy(o.Region)
        .OrderBy(o.OrderDate)),

    PrevAmount = Window.Lag(o.Amount, 1, w => w
        .OrderBy(o.OrderDate)),

    RunningTotal = Window.Sum(o.Amount, w => w
        .PartitionBy(o.Region)
        .OrderBy(o.OrderDate)
        .Rows().UnboundedPreceding().CurrentRow())
});

Available Functions: RowNumber, Rank, DenseRank, PercentRank, NTile, Lag, Lead, FirstValue, LastValue, NthValue, Sum, Avg, Count, Min, Max

See docs/features/window-functions.md for full documentation including fluent API style.

Time Series Gap Filling

Fill gaps in time series data with ClickHouse's WITH FILL and INTERPOLATE clauses:

using EF.CH.Extensions;

// Basic gap filling - insert missing hourly rows
var hourlyData = context.Readings
    .OrderBy(x => x.Hour)
    .Interpolate(x => x.Hour, TimeSpan.FromHours(1));

// With FROM/TO bounds for complete date range
var fullRange = context.Readings
    .OrderBy(x => x.Date)
    .Interpolate(x => x.Date, TimeSpan.FromDays(1), startDate, endDate);

// Forward-fill values from previous row
var filledData = context.Readings
    .OrderBy(x => x.Hour)
    .Interpolate(x => x.Hour, TimeSpan.FromHours(1),
                 x => x.Value, InterpolateMode.Prev);

// Multiple columns with builder
var multiColumn = context.Readings
    .OrderBy(x => x.Hour)
    .Interpolate(x => x.Hour, TimeSpan.FromHours(1), i => i
        .Fill(x => x.Temperature, InterpolateMode.Prev)
        .Fill(x => x.Count, 0));

Step Types:

Type Use Case Example
TimeSpan Hours, minutes, seconds, days TimeSpan.FromHours(1)
ClickHouseInterval Months, quarters, years ClickHouseInterval.Months(1)
int Numeric sequences 10

See docs/features/interpolate.md for full documentation.

Data Skipping Indices

Skip indices allow ClickHouse to skip reading granules that don't match query predicates, dramatically improving query performance for selective filters.

modelBuilder.Entity<LogEvent>(entity =>
{
    entity.UseMergeTree(x => new { x.Timestamp, x.Id });

    // Minmax for datetime range queries
    entity.HasIndex(x => x.Timestamp)
        .UseMinmax()
        .HasGranularity(4);

    // Bloom filter for array membership (has(Tags, 'error'))
    entity.HasIndex(x => x.Tags)
        .UseBloomFilter(falsePositive: 0.025)
        .HasGranularity(3);

    // Token bloom filter for log search (LIKE '%exception%')
    entity.HasIndex(x => x.Message)
        .UseTokenBF(size: 10240, hashes: 3, seed: 0)
        .HasGranularity(4);

    // Set index for low-cardinality columns
    entity.HasIndex(x => x.Status)
        .UseSet(maxRows: 100)
        .HasGranularity(2);
});

Or use attributes:

public class LogEvent
{
    [MinMaxIndex(Granularity = 4)]
    public DateTime Timestamp { get; set; }

    [BloomFilterIndex(FalsePositive = 0.025, Granularity = 3)]
    public string[] Tags { get; set; } = [];

    [TokenBFIndex(Granularity = 4)]
    public string Message { get; set; } = string.Empty;

    [SetIndex(MaxRows = 100, Granularity = 2)]
    public string Status { get; set; } = string.Empty;
}

Index Types:

Type Use Case
UseMinmax() Numeric/datetime range queries
UseBloomFilter(fpp) Exact matching, array membership
UseTokenBF(...) Tokenized text search (logs, URLs)
UseNgramBF(...) Fuzzy/substring text matching
UseSet(maxRows) Low-cardinality exact matching

See docs/features/skip-indices.md for full documentation.

Materialized Views

// LINQ-based (type-safe)
modelBuilder.Entity<HourlySummary>(entity =>
{
    entity.UseSummingMergeTree(x => new { x.Hour, x.ProductId });
    entity.AsMaterializedView<HourlySummary, Order>(
        query: orders => orders
            .GroupBy(o => new { Hour = o.OrderDate.Date, o.ProductId })
            .Select(g => new HourlySummary
            {
                Hour = g.Key.Hour,
                ProductId = g.Key.ProductId,
                OrderCount = g.Count(),
                TotalRevenue = g.Sum(o => o.Total)
            }),
        populate: false);
});

Projections

Projections are table-level optimizations stored alongside the main table data. Unlike materialized views, projections are not separately queryable - the query optimizer automatically uses them when beneficial.

// Sort-order projection - auto-named: orders__prj_ord__customer_id__order_date
entity.HasProjection()
    .OrderBy(x => x.CustomerId)
    .ThenBy(x => x.OrderDate)
    .Build();

// Aggregation projection - explicit name, anonymous type
entity.HasProjection("daily_stats")
    .GroupBy(x => x.OrderDate.Date)
    .Select(g => new {
        Date = g.Key,
        TotalAmount = g.Sum(o => o.Amount),
        OrderCount = g.Count()
    })
    .Build();

// ClickHouse-specific aggregates (uniq, argMax, quantile, etc.)
entity.HasProjection("advanced_stats")
    .GroupBy(x => x.Date)
    .Select(g => new {
        Date = g.Key,
        UniqueUsers = ClickHouseAggregates.Uniq(g, o => o.UserId),
        TopProduct = ClickHouseAggregates.ArgMax(g, o => o.ProductId, o => o.Revenue)
    })
    .Build();

See docs/features/projections.md for full documentation including all ClickHouse aggregate functions.

Aggregate Combinators

ClickHouse aggregate combinators modify aggregate function behavior. Use these for AggregatingMergeTree workflows with full LINQ support:

using EF.CH.Extensions;

// Store aggregate states in byte[] columns
public class HourlySummary
{
    public DateTime Hour { get; set; }
    public byte[] CountState { get; set; } = [];
    public byte[] SumAmountState { get; set; } = [];
    public byte[] AvgTimeState { get; set; } = [];
}

// Configure AggregateFunction columns
modelBuilder.Entity<HourlySummary>(entity =>
{
    entity.HasNoKey();
    entity.UseAggregatingMergeTree(x => x.Hour);

    entity.Property(e => e.CountState).HasAggregateFunction("count", typeof(ulong));
    entity.Property(e => e.SumAmountState).HasAggregateFunction("sum", typeof(long));
    entity.Property(e => e.AvgTimeState).HasAggregateFunction("avg", typeof(double));
});

// Materialize with State combinators
.Select(g => new HourlySummary
{
    Hour = g.Key,
    CountState = g.CountState(),              // countState()
    SumAmountState = g.SumState(x => x.Amount), // sumState(Amount)
    AvgTimeState = g.AvgState(x => x.ResponseTime)
})

// Query with Merge combinators to produce final values
context.HourlySummary
    .GroupBy(s => s.Hour.Date)
    .Select(g => new
    {
        Date = g.Key,
        TotalCount = g.CountMerge(s => s.CountState),     // countMerge()
        TotalAmount = g.SumMerge<HourlySummary, long>(s => s.SumAmountState),
        AvgTime = g.AvgMerge(s => s.AvgTimeState)
    })

// Conditional aggregation with If combinators
.Select(g => new
{
    HighValueCount = g.CountIf(x => x.Amount > 1000),      // countIf()
    HighValueSum = g.SumIf(x => x.Amount, x => x.Amount > 1000)
})

// Array element aggregation
.Select(p => new
{
    TotalPrices = p.Prices.ArraySum(),   // arraySum()
    AvgPrice = p.Prices.ArrayAvg()       // arrayAvg()
})
Combinator Methods Use Case
-State CountState, SumState, AvgState, MinState, MaxState, UniqState, QuantileState Store aggregate state
-Merge CountMerge, SumMerge, AvgMerge, MinMerge, MaxMerge, UniqMerge, QuantileMerge Combine states
-If CountIf, SumIf, AvgIf, MinIf, MaxIf, UniqIf Conditional aggregation
Array* ArraySum, ArrayAvg, ArrayMin, ArrayMax, ArrayCount Array element aggregation

See docs/features/aggregate-combinators.md for full documentation.

Native JSON Type

Query JSON columns with ClickHouse 24.8+ native subcolumn syntax via extension methods.

using EF.CH.Extensions;

// Configure JSON column
modelBuilder.Entity<Event>(entity =>
{
    entity.Property(e => e.Payload)
        .HasColumnType("JSON")
        .HasMaxDynamicPaths(2048);  // Optional
});

// Query with extension methods - translates to subcolumn syntax
var results = await context.Events
    .Where(e => e.Payload.GetPath<string>("user.email") == "test@example.com")
    .Where(e => e.Payload.HasPath("metrics.score"))
    .Select(e => new {
        e.Id,
        Email = e.Payload.GetPath<string>("user.email"),
        Score = e.Payload.GetPathOrDefault<int>("metrics.score", 0),
        FirstTag = e.Payload.GetPath<string>("tags[0]")
    })
    .ToListAsync();

// Generated SQL:
// SELECT "Id", "Payload"."user"."email",
//        ifNull("Payload"."metrics"."score", 0),
//        "Payload"."tags"[1]
// FROM "Events"
// WHERE "Payload"."user"."email" = 'test@example.com'
//   AND "Payload"."metrics"."score" IS NOT NULL

Extension Methods:

Method SQL Description
GetPath<T>(path) "col"."path" Extract typed value
GetPathOrDefault<T>(path, default) ifNull("col"."path", default) With fallback
HasPath(path) "col"."path" IS NOT NULL Check existence
GetArray<T>(path) "col"."path" Extract array

Typed POCO Support:

public class Order
{
    [ClickHouseJson(IsTyped = true)]
    public OrderMetadata Metadata { get; set; } = new();
}

See docs/types/json.md for full documentation.

Dictionaries

ClickHouse dictionaries are in-memory key-value stores for fast lookups:

// Define dictionary entity with marker interface
public class CountryLookup : IClickHouseDictionary
{
    public ulong Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

// Configure in OnModelCreating
entity.AsDictionary<CountryLookup, Country>(cfg => cfg
    .HasKey(x => x.Id)
    .FromTable()
    .UseHashedLayout()
    .HasLifetime(300));

// Use in LINQ queries - translates to dictGet()
var orders = db.Orders
    .Select(o => new {
        o.Id,
        CountryName = db.CountryDict.Get(o.CountryId, c => c.Name)
    });

Layouts: Flat, Hashed, ComplexKeyHashed, Cache, Direct

External Entities

Query remote databases directly through ClickHouse table functions:

// Define external entity (keyless - uses table function, not a ClickHouse table)
public class ExternalCustomer
{
    public int id { get; set; }
    public string name { get; set; } = string.Empty;
    public string email { get; set; } = string.Empty;
}

// Configure in OnModelCreating
modelBuilder.ExternalPostgresEntity<ExternalCustomer>(ext => ext
    .FromTable("customers", schema: "public")
    .Connection(c => c
        .HostPort(env: "PG_HOST")
        .Database(env: "PG_DATABASE")
        .Credentials("PG_USER", "PG_PASSWORD")));

// Query like any other entity - generates postgresql() table function
var customers = await context.ExternalCustomers
    .Where(c => c.name.StartsWith("A"))
    .ToListAsync();

// JOIN with native ClickHouse tables
var orderSummary = await context.Orders
    .Join(context.ExternalCustomers, o => o.CustomerId, c => c.id,
        (o, c) => new { c.name, o.Amount })
    .ToListAsync();

Supported Providers:

Provider Extension Method Use Case
PostgreSQL ExternalPostgresEntity<T>() Direct credentials
MySQL ExternalMySqlEntity<T>() REPLACE INTO, ON DUPLICATE KEY
ODBC ExternalOdbcEntity<T>() SQL Server, Oracle via DSN
Redis ExternalRedisEntity<T>() Key-value with auto-generated schema

See docs/features/external-entities.md for detailed configuration.

Documentation

Topic Description
Getting Started Installation and first project
ClickHouse Concepts Key differences from RDBMS
Table Engines MergeTree family guide
Type Mappings Complete type reference
JSON Types Native JSON with extension method API
Features Materialized views, partitioning, TTL, etc.
Projections Table-level sort and aggregation optimizations
Compression Codecs Per-column compression configuration
Window Functions Ranking, lead/lag, running totals
Data Skipping Indices Bloom filter, minmax, set, and token indices
Time Series Gap Filling WITH FILL and INTERPOLATE for continuous data
Query Modifiers FINAL, SAMPLE, PREWHERE, SETTINGS query hints
Computed Columns MATERIALIZED, ALIAS, DEFAULT expression columns
Aggregate Combinators State, Merge, If, Array combinators for pre-aggregation
External Entities Query remote PostgreSQL, MySQL, Redis, ODBC
Migrations EF Core migrations with ClickHouse
Scaffolding Reverse engineering
Limitations What doesn't work

Samples

Sample Description
QuickStartSample Minimal working example
MigrationSample EF Core migrations
KeylessSample Keyless entities for append-only data
ReplacingMergeTreeSample Deduplication patterns
SummingMergeTreeSample Auto-aggregation with SummingMergeTree
CollapsingMergeTreeSample Row cancellation with sign column
MaterializedViewSample Real-time aggregation
ArrayTypeSample Working with arrays
MapTypeSample Working with Map(K, V) dictionaries
EnumTypeSample ClickHouse enum type mapping
PartitioningSample Table partitioning strategies
QueryModifiersSample Final(), Sample(), PreWhere(), WithSettings()
DeleteStrategiesSample Lightweight vs mutation deletes
OptimizeTableSample Programmatic OPTIMIZE TABLE
DictionarySample In-memory dictionary lookups
DictionaryJoinSample Dictionaries as JOIN replacement
ExternalPostgresSample Query PostgreSQL from ClickHouse
ExternalRedisSample Redis key-value integration
JsonTypeSample Native JSON with subcolumn queries

License

MIT License - see LICENSE for details.

Acknowledgments

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
8.0.7 28 1/8/2026
8.0.6 36 1/8/2026
8.0.5 49 1/7/2026
8.0.4 36 1/7/2026
8.0.3 46 1/6/2026
8.0.2 84 12/31/2025
8.0.1 81 12/31/2025
8.0.0 164 12/23/2025
0.0.25 35 1/8/2026
0.0.24 35 1/7/2026
0.0.23 34 1/7/2026
0.0.22 50 1/6/2026
0.0.21 41 1/6/2026
0.0.20 84 1/1/2026
0.0.19 79 12/31/2025
0.0.18 174 12/23/2025
0.0.17 147 12/21/2025
0.0.16 147 12/21/2025
0.0.15 148 12/21/2025
0.0.14 149 12/21/2025
0.0.13 120 12/21/2025
0.0.12 117 12/20/2025
0.0.11 125 12/20/2025
0.0.10 108 12/20/2025
0.0.9 111 12/20/2025
0.0.8 207 12/19/2025
0.0.7 265 12/19/2025
0.0.6 260 12/18/2025
0.0.5 261 12/17/2025
0.0.4 260 12/17/2025
0.0.3 264 12/15/2025
0.0.2 146 12/14/2025
0.0.1 433 12/9/2025
0.0.0 202 12/4/2025