-
ClickHouseClient(recommandé) : un client de haut niveau, thread-safe, conçu pour être utilisé comme singleton. Il fournit une API asynchrone simple pour les requêtes et les insertions en masse. C’est le meilleur choix pour la plupart des applications. -
ADO.NET (
ClickHouseDataSource,ClickHouseConnection,ClickHouseCommand) : les abstractions standard de base de données de .NET. Indispensable pour l’intégration avec les ORM (Dapper, Linq2db) et lorsque vous avez besoin de la compatibilité ADO.NET.ClickHouseBulkCopyest une classe utilitaire qui permet d’insérer efficacement des données à l’aide d’une connexion ADO.NET.ClickHouseBulkCopyest obsolète et sera supprimé dans une prochaine version ; utilisez plutôtClickHouseClient.InsertBinaryAsync.
Guide de migration
- Mettez à jour votre fichier
.csprojavec le nouveau nom du paquetClickHouse.Driveret la dernière version disponible sur NuGet. - Remplacez dans votre code toutes les références à
ClickHouse.ClientparClickHouse.Driver.
Versions de .NET prises en charge
ClickHouse.Driver prend en charge les versions de .NET suivantes :
- .NET 6.0
- .NET 8.0
- .NET 9.0
- .NET 10.0
Installation
Démarrage rapide
Configuration
- Chaîne de connexion : paires clé-valeur séparées par des points-virgules, qui indiquent l’hôte, les informations d’authentification et d’autres options de connexion.
- Objet
ClickHouseClientSettings: objet de configuration fortement typé, qui peut être chargé depuis des fichiers de configuration ou défini dans le code.
Paramètres de connexion
Format des données et sérialisation
Gestion des sessions
L’option
UseSession active la persistance de la session du serveur, ce qui permet d’utiliser des instructions SET et des tables temporaires. Les sessions sont réinitialisées après 60 secondes d’inactivité (délai d’expiration par défaut). La durée de vie de la session peut être prolongée en définissant des paramètres de session via des instructions ClickHouse ou la configuration du serveur.La classe ClickHouseConnection permet normalement un fonctionnement en parallèle (plusieurs threads peuvent exécuter des requêtes simultanément). Toutefois, l’activation de l’option UseSession limite cela à une seule requête active par connexion à un instant donné (il s’agit d’une limitation côté serveur).Sécurité
Configuration du client HTTP
Journalisation et débogage
Paramètres personnalisés et rôles
Lorsque vous utilisez une chaîne de connexion pour définir des paramètres personnalisés, utilisez le préfixe
set_, par ex. : “set_max_threads=4”. Si vous utilisez un objet ClickHouseClientSettings, n’utilisez pas le préfixe set_.Pour obtenir la liste complète des paramètres disponibles, consultez cette page.Exemples de chaînes de connexion
Connexion de base
Avec des paramètres ClickHouse personnalisés
QueryOptions
QueryOptions vous permet de surcharger les paramètres définis au niveau du client pour chaque requête. Toutes les propriétés sont facultatives et ne remplacent les valeurs par défaut du client que lorsqu’elles sont spécifiées.
Exemple :
InsertOptions
InsertOptions étend QueryOptions avec des paramètres spécifiques aux opérations d’insertion en masse via InsertBinaryAsync.
Toutes les propriétés de
QueryOptions sont également disponibles dans InsertOptions.
Exemple :
Ignorer la requête de sondage du schéma
InsertBinaryAsync envoie une requête SELECT ... WHERE 1=0 avant chaque insertion afin d’identifier les types de colonnes. Pour les scénarios à haut débit, vous pouvez supprimer cette surcharge de deux façons :
Option 1 : fournir explicitement les types de colonnes
Lorsque vous connaissez le schéma de la table à la compilation, transmettez-le directement via ColumnTypes. Aucune requête de schéma n’est alors envoyée :
UseSchemaCache = true pour n’interroger le schéma qu’une seule fois et le réutiliser lors des insertions suivantes sur la même instance ClickHouseClient :
ColumnTypesest prioritaire surUseSchemaCache. Si les deux sont définis, les types explicites sont utilisés.- Le cache de schéma ne détecte pas les modifications apportées via
ALTER TABLE. Si vous modifiez le schéma de la table, créez un nouveauClickHouseClientou évitezUseSchemaCachepour cette table. - Le cache est propre à l’instance
ClickHouseClientet indexé par (database, table). Différents sous-ensembles de colonnes d’une même table partagent un schéma mis en cache unique.
ClickHouseClient
ClickHouseClient est l’API recommandée pour interagir avec ClickHouse. Il est thread-safe, conçu pour être utilisé comme singleton et gère en interne le pool de connexions HTTP.
Créer un client
ClickHouseClient à l’aide d’une chaîne de connexion ou d’un objet ClickHouseClientSettings. Consultez la section Configuration pour connaître les options disponibles.
Les informations de votre service ClickHouse Cloud sont disponibles dans la ClickHouse Cloud console.
Sélectionnez un service, puis cliquez sur Connect :
Choisissez C#. Les détails de connexion s’affichent ci-dessous.
Si vous utilisez ClickHouse autogéré, les détails de connexion sont définis par votre administrateur ClickHouse.
Avec une chaîne de connexion :
ClickHouseClientSettings :
IHttpClientFactory :
ClickHouseClient est conçu pour être conservé sur la durée et partagé dans toute votre application. Créez-le une seule fois (généralement sous forme de singleton) et réutilisez-le pour toutes les opérations sur la base de données. Le client gère en interne le pool de connexions HTTP.Exécution des requêtes
ExecuteNonQueryAsync pour les instructions qui ne renvoient pas de résultats :
ExecuteScalarAsync pour récupérer une seule valeur :
Insérer des données
Insertions paramétrées
ExecuteNonQueryAsync. Les types des paramètres doivent être spécifiés dans le SQL à l’aide de la syntaxe {name:Type} :
Insertions en masse
InsertBinaryAsync pour insérer efficacement un grand nombre de lignes. Il transmet les données en flux à l’aide du format binaire natif de lignes de ClickHouse, prend en charge les envois parallèles par lots et évite les erreurs “URL trop longue” qui peuvent survenir avec les requêtes paramétrées.
InsertOptions :
- Le client récupère automatiquement la structure de la table via
SELECT * FROM <table> WHERE 1=0avant d’insérer les données. Les valeurs fournies doivent correspondre aux types des colonnes cibles. Pour ignorer cette requête, utilisezInsertOptions.ColumnTypesouInsertOptions.UseSchemaCache. - Lorsque
MaxDegreeOfParallelism > 1, les batches sont envoyés en parallèle. Les sessions ne sont pas compatibles avec l’insertion en parallèle ; désactivez-les ou définissezMaxDegreeOfParallelism = 1. - Utilisez
RowBinaryFormat.RowBinaryWithDefaultsdansInsertOptions.Formatsi vous souhaitez que le serveur applique les valeurs DEFAULT aux colonnes non fournies.
Insertion de POCO
object[], vous pouvez insérer directement des objets POCO fortement typés. Enregistrez le type une seule fois, puis passez IEnumerable<T> :
Lorsque toutes les propriétés mappées spécifient un
Type explicite, la requête de sondage du schéma est entièrement omise. Lorsque seules certaines propriétés ont des types explicites, le pilote revient à la requête de sondage du schéma pour l’ensemble des colonnes.
InsertBinaryAsync<T> prend en charge les mêmes InsertOptions (batching, parallélisme, mise en cache du schéma) que la surcharge object[].
Contrairement à la surcharge
object[], InsertBinaryAsync<T> n’accepte pas de liste explicite de colonnes. Les colonnes sont déterminées par les propriétés mappées du type enregistré. Pour contrôler les colonnes insérées, utilisez [ClickHouseNotMapped] pour exclure des propriétés ou [ClickHouseColumn(Name = "...")] pour les renommer.Si ColumnTypes est défini dans InsertOptions, elles remplaceront les attributs POCO.Évolution du schéma
DEFAULT (ou d’autres expressions par défaut) est automatiquement remplie par le serveur. Aucune modification du code ni aucun nouvel enregistrement ne sont nécessaires.
Lecture des données
ExecuteReaderAsync pour exécuter des requêtes SELECT. Le ClickHouseDataReader renvoyé fournit un accès typé aux colonnes de résultat via des méthodes comme GetInt64(), GetString() et GetFieldValue<T>().
Appelez Read() pour passer à la ligne suivante. Cette méthode renvoie false lorsqu’il n’y a plus de lignes. Accédez aux colonnes par index (à partir de 0) ou par nom de colonne.
Paramètres SQL
{parameter_name:DataType}.
Exemples :
Les paramètres SQL ‘bind’ sont transmis sous forme de paramètres de requête dans l’URI HTTP. En utiliser un trop grand nombre peut donc entraîner une exception “URL too long”. Utilisez
InsertBinaryAsync pour l’insertion en masse de données afin d’éviter cette limitation.ID de requête
query_id unique, qui peut être utilisé pour extraire des données de la table system.query_log ou annuler des requêtes de longue durée. Vous pouvez spécifier un ID de requête personnalisé via QueryOptions:
Correspondance personnalisée des types de paramètres
@ (par exemple, WHERE id = @id), le driver déduit automatiquement le type ClickHouse à partir du type de valeur .NET. Par exemple, int correspond à Int32 et DateTime à DateTime.
Pour remplacer ces valeurs par défaut, définissez ParameterTypeResolver dans ClickHouseClientSettings. C’est utile si vous voulez que tous les paramètres DateTime utilisent DateTime64(3) pour une précision à la milliseconde, ou que toutes les valeurs décimales utilisent une échelle spécifique, sans avoir à définir ClickHouseType sur chaque paramètre individuellement.
Utilisation de DictionaryParameterTypeResolver pour des correspondances de types simples :
IParameterTypeResolver personnalisé pour les cas d’usage avancés :
Pour une résolution basée sur le nom ou tenant compte de la valeur, implémentez directement l’interface IParameterTypeResolver. Renvoyez null pour utiliser l’inférence par défaut :
QueryOptions.ParameterTypeResolver. Lorsqu’il est défini, il prévaut sur le résolveur défini au niveau du client.
Ordre de priorité pour la résolution des types :
Le résolveur s’inscrit lui aussi dans une chaîne de priorité. De la priorité la plus élevée à la plus faible :
ClickHouseTypeexplicite défini sur le paramètre- Indice de type SQL issu de la syntaxe
{name:Type}dans la requête IParameterTypeResolver(viaQueryOptions.ParameterTypeResolver, avec repli surClickHouseClientSettings.ParameterTypeResolver)- Inférence de type intégrée (
TypeConverter.ToClickHouseType)
ClickHouseConnection d’ADO.NET : les paramètres de configuration sont hérités par les connexions créées à partir du client.
Flux brut
ExecuteRawResultAsync pour transmettre directement le résultat de la requête dans un format spécifique, sans passer par le lecteur de données. Cela est utile pour exporter des données vers des fichiers ou les acheminer vers d’autres systèmes :
JSONEachRow, CSV, TSV, Parquet, Native. Consultez la documentation des formats pour voir toutes les options.
Insertion de flux bruts
InsertRawStreamAsync pour insérer des données directement à partir de flux de fichier ou de mémoire, dans des formats comme CSV, JSON, Parquet ou tout format ClickHouse pris en charge.
Insérer à partir d’un fichier CSV :
Consultez la documentation des paramètres de format pour découvrir les options qui permettent de contrôler le comportement de l’ingestion de données.
Autres exemples
ADO.NET
ClickHouseConnection, ClickHouseCommand et ClickHouseDataReader. Cette API est nécessaire pour l’intégration avec les ORM (Dapper, Linq2db) et lorsque vous avez besoin des abstractions .NET standard pour les bases de données.
Gestion du cycle de vie avec ClickHouseDataSource
ClickHouseDataSource afin de garantir une gestion correcte du cycle de vie ainsi qu’un pool de connexions. Le ClickHouseDataSource gère en interne une unique instance de ClickHouseClient, et toutes les connexions partagent son pool de connexions HTTP.
Utilisation de ClickHouseCommand
ExecuteNonQueryAsync()- Pour les instructions INSERT, UPDATE, DELETE et DDLExecuteScalarAsync()- Renvoie la première colonne de la première ligneExecuteReaderAsync()- Renvoie unClickHouseDataReaderpermettant de parcourir les résultats
Utilisation de ClickHouseDataReader
ClickHouseDataReader permet un accès typé au résultat de la requête :
Bonnes pratiques
Durée de vie des connexions et pool de connexions
ClickHouse.Driver utilise System.Net.Http.HttpClient en interne. HttpClient dispose d’un pool de connexions par endpoint. Par conséquent :
- Les sessions de base de données sont multiplexées via des connexions HTTP gérées par le pool de connexions.
- Les connexions HTTP sont automatiquement recyclées par le pool.
- Les connexions peuvent rester actives après la libération des objets
ClickHouseClientouClickHouseConnection.
Gestion des valeurs DateTime
-
Utilisez UTC chaque fois que possible. Stockez les horodatages dans des colonnes
DateTime('UTC')et utilisezDateTimeKind.Utcdans votre code. Cela élimine toute ambiguïté liée au fuseau horaire. -
Utilisez
DateTimeOffsetpour gérer explicitement le fuseau horaire. Il représente toujours un instant précis et inclut les informations de décalage. -
Spécifiez le fuseau horaire dans les annotations de type SQL. Lorsque vous utilisez des paramètres avec des valeurs DateTime
Unspecifiedpour des colonnes non UTC, incluez le fuseau horaire dans le SQL :
Insertions asynchrones
CustomSettings ou la chaîne de connexion :
wait_for_async_insert) :
Paramètres clés :
Sessions
- Tables temporaires (
CREATE TEMPORARY TABLE) - Conservation du contexte de requête d’une instruction à l’autre
- Paramètres de session (
SET max_threads = 4)
Types de données pris en charge
ClickHouse.Driver prend en charge tous les types de données de ClickHouse. Les tableaux ci-dessous présentent les correspondances entre les types ClickHouse et les types .NET natifs lors de la lecture des données depuis la base de données.
Correspondance de types : lecture à partir de ClickHouse
Types d’entiers
Types à virgule flottante
Types décimaux
La conversion du type Decimal est gérée par le paramètre UseCustomDecimals.
Type booléen
Types de chaînes
Par défaut, les colonnes
String et FixedString(N) sont toutes deux renvoyées sous forme de string. Définissez ReadStringsAsByteArrays=true dans votre chaîne de connexion pour les lire sous forme de byte[]. Cela est utile lorsque vous stockez des données binaires qui peuvent ne pas être en UTF-8 valide.Types de date et d’heure
ClickHouse stocke les valeurs
DateTime et DateTime64 en interne sous forme de timestamps Unix (secondes ou fractions de seconde écoulées depuis l’époque). Bien que le stockage soit toujours en UTC, les colonnes peuvent avoir un fuseau horaire associé, qui influe sur la manière dont les valeurs sont affichées et interprétées.
Lors de la lecture de valeurs DateTime, la propriété DateTime.Kind est définie en fonction du fuseau horaire de la colonne :
Pour les colonnes non UTC, le
DateTime renvoyé représente l’heure d’horloge dans ce fuseau horaire. Utilisez ClickHouseDataReader.GetDateTimeOffset() pour obtenir un DateTimeOffset avec le décalage correct pour ce fuseau horaire :
DateTime au lieu de DateTime('Europe/Amsterdam')), le pilote renvoie un DateTime avec Kind=Unspecified. Cela préserve exactement l’heure telle qu’elle est stockée, sans supposer de fuseau horaire.
Si vous avez besoin d’un comportement tenant compte du fuseau horaire pour des colonnes sans fuseau horaire explicite, vous pouvez :
- Utiliser des fuseaux horaires explicites dans vos définitions de colonnes :
DateTime('UTC')ouDateTime('Europe/Amsterdam') - Appliquer vous-même le fuseau horaire après la lecture.
Type JSON
Le type de retour des colonnes JSON dépend du paramètre
JsonReadMode :
-
Binary(par défaut) : renvoieSystem.Text.Json.Nodes.JsonObject. Fournit un accès structuré aux données JSON, mais les types ClickHouse spécialisés (comme les adresses IP, les UUID ou les grands nombres décimaux) sont convertis en représentations sous forme de chaîne dans la structure JSON. -
String: renvoie le JSON brut sous forme destring. Préserve la représentation JSON exacte de ClickHouse, ce qui est utile lorsque vous devez transmettre le JSON sans l’analyser, ou lorsque vous souhaitez gérer vous-même la désérialisation.
Autres types
Les types Dynamic et Variant sont convertis dans le type correspondant au type sous-jacent réel de chaque ligne.
Types de géométrie
Le type Geometry est un type Variant qui peut contenir n’importe quel type de géométrie. Il sera converti en type correspondant.
Correspondance des types : écriture dans ClickHouse
Types entiers
Types en virgule flottante
Type Boolean
Types de chaînes
Types de date et d’heure
Le driver respecte
DateTime.Kind lors de l’écriture des valeurs :
Les valeurs
DateTimeOffset préservent toujours l’instant exact.
Exemple : DateTime UTC (instant préservé)
DateTimeKind.Utc ou DateTimeOffset pour toutes les opérations sur les types DateTime. Cela garantit que votre code fonctionne de manière cohérente, quel que soit le fuseau horaire du serveur, du client ou de la colonne.
Paramètres HTTP vs copie en masse
Unspecified :
Copie en masse connaît le fuseau horaire de la colonne cible et interprète correctement les valeurs Unspecified dans ce fuseau horaire.
Paramètres HTTP ne connaissent pas automatiquement le fuseau horaire de la colonne. Vous devez le spécifier dans l’indication de type SQL :
Types décimaux
Type JSON
Le comportement lors de l’écriture de JSON est contrôlé par le paramètre
JsonWriteMode :
-
String(par défaut) : Acceptestring,JsonObject,JsonNodeou tout objet. Toutes les entrées sont sérialisées viaSystem.Text.Json.JsonSerializeret envoyées sous forme de chaînes JSON pour un traitement côté serveur. C’est le mode le plus flexible et il fonctionne sans enregistrement préalable de type. -
Binary: Accepte uniquement les types POCO enregistrés. Les données sont converties côté client au format JSON binaire de ClickHouse avec une prise en charge complète des indications de type. Nécessite d’appelerconnection.RegisterJsonSerializationType<T>()avant utilisation. L’écriture de valeursstringouJsonNodedans ce mode lèveArgumentException.
Colonnes JSON typées
JSON(id UInt64, price Decimal128(2))), le driver utilise ces indications pour sérialiser les valeurs en respectant pleinement les types. Cela préserve la précision de types comme UInt64, Decimal, UUID et DateTime64, qui perdraient sinon en précision s’ils étaient sérialisés sous forme de JSON générique.
Sérialisation des POCO
JsonWriteMode :
Mode String (par défaut) : les POCO sont sérialisés via System.Text.Json.JsonSerializer. Aucun enregistrement de type n’est nécessaire. C’est l’approche la plus simple, et elle fonctionne avec les objets anonymes.
Mode binaire : les POCO sont sérialisés à l’aide du format JSON binaire du driver, avec prise en charge complète des indications de type. Les types doivent être enregistrés avec connection.RegisterJsonSerializationType<T>() avant utilisation. Ce mode prend en charge des mappages de chemins personnalisés via des attributs :
-
[ClickHouseJsonPath("path")]: associe une propriété à un chemin JSON personnalisé. Utile pour les structures imbriquées ou lorsque le nom de la propriété diffère de la clé JSON souhaitée. Fonctionne uniquement en mode binaire. -
[ClickHouseJsonIgnore]: exclut une propriété de la sérialisation. Fonctionne uniquement en mode binaire.
UserId ne correspondra qu’à une indication définie comme UserId, et non userid. Cela correspond au comportement de ClickHouse, qui permet à des chemins comme userName et UserName de coexister en tant que champs distincts.
Limitations (mode binaire uniquement) :
- Les types POCO doivent être enregistrés sur la connexion avec
connection.RegisterJsonSerializationType<T>()avant la sérialisation. Toute tentative de sérialiser un type non enregistré lève uneClickHouseJsonSerializationException. - Les propriétés de type Dictionary et array/list nécessitent des indications de type dans la définition de la colonne pour être sérialisées correctement. Sans ces indications, utilisez plutôt String mode.
- Les valeurs nulles des propriétés POCO ne sont écrites que lorsque le chemin possède une indication de type
Nullable(T)dans la définition de la colonne. ClickHouse n’autorise pas les typesNullabledans les chemins JSON dynamiques ; les propriétés nulles sans indication sont donc ignorées. - Les attributs
ClickHouseJsonPathetClickHouseJsonIgnoresont ignorés en String mode (ils ne fonctionnent qu’en mode binaire).
Autres types
Types de géométrie
Non pris en charge en écriture
Gestion du type Nested
Nested(...)) peuvent être lus et écrits avec la sémantique des tableaux.
Journalisation et diagnostics
Microsoft.Extensions.Logging afin d’offrir une journalisation légère, activée sur demande. Lorsqu’elle est activée, le driver émet des messages structurés pour les événements du cycle de vie de la connexion, l’exécution des commandes, les opérations de transport et les opérations d’insertion en masse. La journalisation est entièrement facultative : les applications qui ne configurent pas de logger continuent de s’exécuter sans surcharge supplémentaire.
Démarrage rapide
Utilisation du fichier appsettings.json
Utilisation d’une configuration en mémoire
Catégories et émetteurs
Exemple : diagnostic des problèmes de connexion
- Sélection de la fabrique de clients HTTP (pool par défaut ou connexion unique)
- Configuration du gestionnaire HTTP (SocketsHttpHandler ou HttpClientHandler)
- Paramètres du pool de connexions (MaxConnectionsPerServer, PooledConnectionLifetime, etc.)
- Paramètres de délai d’expiration (ConnectTimeout, Expect100ContinueTimeout, etc.)
- Configuration SSL/TLS
- Événements d’ouverture/fermeture des connexions
- Suivi des ID de session
Mode Débogage : tracing réseau et diagnostics
ClickHouse.Driver.Diagnostic.TraceHelper). Les événements seront consignés dans la catégorie ClickHouse.Driver.NetTrace. Avertissement : cela générera des logs extrêmement verbeux et aura un impact sur les performances. Il n’est pas recommandé d’activer le mode Débogage en production.
OpenTelemetry
System.Diagnostics.Activity. Lorsqu’il est activé, le driver émet des spans pour les opérations sur la base de données, qui peuvent être exportés vers des backends d’observabilité comme Jaeger ou ClickHouse lui-même (via l’OpenTelemetry Collector).
Activer le tracing
ActivitySource du driver ClickHouse à votre configuration OpenTelemetry :
Attributs des spans
Options de configuration
ClickHouseDiagnosticsOptions :
Configuration TLS
Validation personnalisée des certificats
HttpClient avec un gestionnaire ServerCertificateCustomValidationCallback configuré :
Points importants à prendre en compte lors de la fourniture d’un HttpClient personnalisé
- Décompression automatique : vous devez activer
AutomaticDecompressionsi la compression n’est pas désactivée (elle est activée par défaut). - Délai d’inactivité : définissez
PooledConnectionIdleTimeoutsur une valeur inférieure aukeep_alive_timeoutdu serveur (10 secondes pour ClickHouse Cloud) afin d’éviter les erreurs de connexion dues à des connexions semi-ouvertes.
Prise en charge des ORM
ClickHouseConnection). Pour gérer correctement le cycle de vie des connexions, créez-les à partir d’un ClickHouseDataSource :
Dapper
ClickHouse.Driver est compatible avec Dapper. Le pilote convertit automatiquement la syntaxe @parameter de Dapper en syntaxe native {parameter:Type} de ClickHouse, en déduisant les types à partir des valeurs .NET.
Utilisez ClickHouseDataSource pour gérer correctement le cycle de vie de la connexion :
Modes de passage des paramètres
DynamicParameters (à partir d’un dictionnaire ou d’un objet anonyme) :
Requêtes vers des POCO
Syntaxe native des paramètres ClickHouse
{param:Type} de ClickHouse avec un Dictionary<string, object> pour les valeurs de paramètre. N’utilisez pas à la fois la syntaxe @param et la syntaxe {param:Type} pour un même paramètre.
WHERE IN
WHERE id IN (@Ids1, @Ids2, @Ids3), et le driver convertit chaque paramètre étendu.
La fonction has() de ClickHouse avec un paramètre Array fonctionne également :
Gestionnaires de types personnalisés
ITuple, BigInteger et ClickHouseDecimal, nécessitent l’enregistrement de gestionnaires au démarrage :
Dapper.Contrib
GetAll<T>() et Get<T>(id) fonctionnent. En revanche, Insert<T>() ne fonctionne pas : il génère une syntaxe SQL Server (SCOPE_IDENTITY, []). Il est recommandé d’utiliser à la place la méthode native InsertBinaryAsync de ClickHouseClient.
Limitations
Linq2db
DataConnection à l’aide du fournisseur ClickHouse :
BulkCopyAsync pour effectuer efficacement des insertions en bloc.
Entity Framework Core
SaveChanges — le tout avec les conventions EF Core habituelles.
- NuGet :
ClickHouse.EntityFrameworkCore - Source : GitHub
Ce fournisseur est activement développé. La version actuelle prend en charge les requêtes LINQ (y compris les JOIN, les sous-requêtes et les opérations ensemblistes),
INSERT via SaveChanges / BulkInsertAsync, les migrations avec DDL complet (CREATE / ALTER / DROP), ainsi que la configuration du moteur de table spécifique à ClickHouse. UPDATE / DELETE ne sont pas pris en charge.Installation
Démarrage rapide
DbContext, puis effectuez des requêtes avec LINQ :
Types pris en charge
Utilisez
ClickHouseDecimal (de ClickHouse.Driver.Numerics) au lieu de decimal lorsque vous avez besoin de toute la précision des colonnes Decimal128/Decimal256 — decimal en .NET est limité à 28–29 chiffres significatifs.
Opérations LINQ prises en charge
Where, OrderBy, Take, Skip, Select, First, Single, Any, All, Count, Distinct, AsNoTracking
GROUP BY et agrégats : GroupBy avec Count, LongCount, Sum, Average, Min, Max — y compris HAVING (.Where() après .GroupBy()), plusieurs agrégats dans une même projection et OrderBy sur les résultats agrégés.
JOINs : Join (INNER), schémas GroupJoin/SelectMany (LEFT et CROSS). LEFT JOIN renvoie de vraies valeurs null pour les lignes sans correspondance (voir la sémantique des valeurs nulles de LEFT JOIN ci-dessous).
Sous-requêtes : Contains / IN corrélés, Any / EXISTS, All, et sous-requêtes scalaires dans les projections.
Opérations ensemblistes : Concat (→ UNION ALL), Union (→ UNION DISTINCT), Intersect, Except.
Collections locales en mémoire : les joins et Contains sur des collections en mémoire (int[], List<T>, etc.) sont traduits en une série de UNION.
Méthodes de chaîne : Contains, StartsWith, EndsWith, IndexOf, Replace, Substring, Trim/TrimStart/TrimEnd, ToLower, ToUpper, Length, IsNullOrEmpty, Concat (et l’opérateur +).
Fonctions mathématiques : les méthodes standard de Math et MathF sont traduites en leurs équivalents ClickHouse — fonctions arithmétiques, logarithmiques, trigonométriques et utilitaires.
Sémantique des valeurs nulles de LEFT JOIN
set_join_use_nulls=1 dans chaque chemin de connexion afin de correspondre aux attentes d’Entity Framework concernant le comportement des JOIN.
Si votre serveur ClickHouse ou votre profil interdit la modification de ce paramètre (par exemple, un profil readonly=1), désactivez ce comportement avec :
0 / "" plutôt que == null.
Insertion de données
SaveChanges utilise l’API native InsertBinaryAsync du pilote — l’encodage RowBinary avec compression GZip est bien plus efficace que le SQL paramétré :
Added à Unchanged après la sauvegarde, comme avec tout autre fournisseur EF Core.
La taille du lot est configurable (1000 par défaut) :
Insertion en masse
BulkInsertAsync au lieu de SaveChanges. Il s’agit d’une méthode d’extension sur DbContext qui contourne entièrement le suivi des modifications d’EF Core, la résolution des identités et la gestion d’état — elle appelle directement InsertBinaryAsync du pilote avec l’encodage RowBinary et la compression GZip.
Cette méthode convient donc au chargement de grands ensembles de données lorsque vous n’avez pas besoin du suivi des entités après l’insertion :
IEnumerable<T> — les entités sont traitées en flux, sans être toutes chargées en mémoire. La valeur de retour est le nombre de lignes insérées. Les entités ne sont pas rattachées au DbContext après l’insertion, il n’y a donc pas de transition d’état Added → Unchanged.
Énumérations
Enum8/Enum16 peuvent être mappées sur des propriétés string ou sur des types C# enum. Lorsqu’on utilise des énumérations C#, le fournisseur convertit automatiquement l’énumération depuis et vers sa représentation sous forme de chaîne :
Conversions de type personnalisées
ValueConverter d’EF Core vous permet d’associer des types personnalisés à des types déjà pris en charge par le fournisseur. Le fournisseur ne voit jamais votre type personnalisé — EF Core effectue la conversion à la limite entre les deux.
Conversion par propriété :
Annotations de type de colonne
string, int, DateTime, etc., le fournisseur détermine automatiquement le type ClickHouse. Pour les types paramétrés et les wrappers, vous devez spécifier explicitement le type ClickHouse.
Utilisation des annotations de données (attributs) :
OnModelCreating :
Array(Nullable(Int32)) et LowCardinality(Nullable(String)) sont pris en charge — le fournisseur retire automatiquement les wrappers Nullable et LowCardinality à chaque niveau d’imbrication.
Colonnes Variant et Dynamic
Variant(T1, T2, ...) et Dynamic sont mappées à object. Comme object est trop générique pour une inférence de type automatique, vous devez déclarer explicitement le type de stockage via .HasColumnType() :
string, ulong, ulong[]).
Colonnes JSON
Json de ClickHouse, qu’il associe à System.Text.Json.Nodes.JsonNode (par défaut) ou à string (via un ValueConverter automatique) :
SaveChanges et BulkInsertAsync :
string avec un type de colonne Json — le fournisseur applique automatiquement un ValueConverter :
- Pas de traduction des chemins JSON —
entity.Data["name"]dans LINQ n’est pas converti en syntaxe SQL ClickHousedata.name. Filtrez sur des colonnes non JSON et examinez le JSON en mémoire. - Sémantique de NULL — le type JSON de ClickHouse renvoie
{}(objet vide) pour les valeurs NULL au lieu de SQL NULL. - Précision des entiers — le JSON de ClickHouse stocke tous les entiers en
Int64. Lors de la lecture viaJsonNode, utilisezGetValue<long>()plutôt queGetValue<int>().
Moteurs de table
ToTable(name, t => ...). Si aucun moteur n’est configuré, le fournisseur utilise par défaut MergeTree, avec ORDER BY déduit de la clé primaire de l’entité.
Clauses du moteur :
WithOrderBy, WithPartitionBy, WithPrimaryKey, WithSampleBy, WithTtl, WithSettings. Elles s’appliquent toutes au builder de moteur renvoyé par HasXxxEngine().
Fonctionnalités au niveau des colonnes : HasCodec, HasTtl, HasComment, HasDefault — toutes sont prises en compte dans les migrations.
Index de saut de données — via HasIndex(...).HasSkippingIndexType(...):
Migrations
Limitations des migrations
Au-delà des migrations, le fournisseur ne prend pas encore en charge :
UPDATE/DELETE- Transactions :
BeginTransactionest sans effet. Les transactions ACID ne sont pas prises en charge dans ClickHouse. - Traduction des requêtes avec chemin JSON :
entity.Data["key"]dans LINQ ne se traduit pas en syntaxe SQL ClickHousedata.key. Filtrez sur des colonnes non JSON et inspectez le JSON en mémoire.
Limites
Colonnes de type AggregateFunction
AggregateFunction(...) ne peuvent pas être interrogées ni faire l’objet d’une insertion directe.
Pour insérer :