Passer au contenu principal
Le client C# officiel pour se connecter à ClickHouse. Le code source du client est disponible dans le dépôt GitHub. Développé à l’origine par Oleg V. Kozlyuk. La bibliothèque propose deux API principales :
  • 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. ClickHouseBulkCopy est une classe utilitaire qui permet d’insérer efficacement des données à l’aide d’une connexion ADO.NET. ClickHouseBulkCopy est obsolète et sera supprimé dans une prochaine version ; utilisez plutôt ClickHouseClient.InsertBinaryAsync.
Les deux API partagent le même pool de connexions HTTP sous-jacent et peuvent être utilisées ensemble dans la même application.

Guide de migration

  1. Mettez à jour votre fichier .csproj avec le nouveau nom du paquet ClickHouse.Driver et la dernière version disponible sur NuGet.
  2. Remplacez dans votre code toutes les références à ClickHouse.Client par ClickHouse.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

Installez le paquet à partir de NuGet :
Ou avec le gestionnaire de packages NuGet :

Démarrage rapide

Configuration

Il existe deux façons de configurer votre connexion à ClickHouse :
  • 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.
Vous trouverez ci-dessous la liste complète de tous les paramètres, de leurs valeurs par défaut et de leurs effets.

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

Par défaut, 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 :
Option 2 : Mettre en cache le schéma Lorsque vous effectuez plusieurs insertions dans la même table, définissez 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 :
  • ColumnTypes est prioritaire sur UseSchemaCache. 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 nouveau ClickHouseClient ou évitez UseSchemaCache pour cette table.
  • Le cache est propre à l’instance ClickHouseClient et 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

Créez un 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 :
Ou avec ClickHouseClientSettings :
Pour les cas d’injection de dépendances, utilisez 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

Utilisez ExecuteNonQueryAsync pour les instructions qui ne renvoient pas de résultats :
Utilisez ExecuteScalarAsync pour récupérer une seule valeur :

Insérer des données

Insertions paramétrées

Insérez des données à l’aide de requêtes paramétrées avec ExecuteNonQueryAsync. Les types des paramètres doivent être spécifiés dans le SQL à l’aide de la syntaxe {name:Type} :

Insertions en masse

Utilisez 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.
Pour les jeux de données volumineux, configurez l’envoi par lots et le parallélisme avec InsertOptions :
  • Le client récupère automatiquement la structure de la table via SELECT * FROM <table> WHERE 1=0 avant d’insérer les données. Les valeurs fournies doivent correspondre aux types des colonnes cibles. Pour ignorer cette requête, utilisez InsertOptions.ColumnTypes ou InsertOptions.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éfinissez MaxDegreeOfParallelism = 1.
  • Utilisez RowBinaryFormat.RowBinaryWithDefaults dans InsertOptions.Format si vous souhaitez que le serveur applique les valeurs DEFAULT aux colonnes non fournies.

Insertion de POCO

Au lieu de construire des tableaux object[], vous pouvez insérer directement des objets POCO fortement typés. Enregistrez le type une seule fois, puis passez IEnumerable<T> :
Par défaut, toutes les propriétés publiques accessibles en lecture sont associées à des colonnes selon une correspondance stricte des noms, sensible à la casse. Vous pouvez personnaliser ce mappage à l’aide d’attributs :
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

Les insertions de POCO fonctionnent de façon transparente lorsque des colonnes sont ajoutées à la table cible après l’enregistrement du type. Comme le pilote n’insère que les colonnes associées au POCO, toute nouvelle colonne avec 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

Utilisez 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

Dans ClickHouse, le format standard des paramètres dans les requêtes SQL est {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

Chaque requête se voit attribuer un 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:
Si vous définissez un QueryId personnalisé, assurez-vous qu’il soit unique à chaque appel. Un GUID aléatoire est un bon choix.

Correspondance personnalisée des types de paramètres

Lorsque vous utilisez des paramètres de style @ (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 :
Vous pouvez également définir un résolveur pour une seule requête via 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 :
  1. ClickHouseType explicite défini sur le paramètre
  2. Indice de type SQL issu de la syntaxe {name:Type} dans la requête
  3. IParameterTypeResolver (via QueryOptions.ParameterTypeResolver, avec repli sur ClickHouseClientSettings.ParameterTypeResolver)
  4. Inférence de type intégrée (TypeConverter.ToClickHouseType)
Le résolveur fonctionne également avec le chemin ClickHouseConnection d’ADO.NET : les paramètres de configuration sont hérités par les connexions créées à partir du client.

Flux brut

Utilisez 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 :
Formats courants : JSONEachRow, CSV, TSV, Parquet, Native. Consultez la documentation des formats pour voir toutes les options.

Insertion de flux bruts

Utilisez 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

Pour d’autres exemples pratiques d’utilisation, consultez le répertoire examples du dépôt GitHub.

ADO.NET

La bibliothèque offre une prise en charge complète d’ADO.NET via 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

Créez toujours des connexions à partir d’un 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.
Avec l’injection de dépendances :
Ne créez pas ClickHouseConnection directement dans le code de production. Chaque instanciation directe crée un nouveau client HTTP et un nouveau pool de connexions, ce qui peut entraîner un épuisement des sockets en cas de charge :
Utilisez toujours ClickHouseDataSource à la place, ou partagez une unique instance de ClickHouseClient.

Utilisation de ClickHouseCommand

Créez des commandes à partir d’une connexion pour exécuter des requêtes SQL :
Méthodes de commande :
  • ExecuteNonQueryAsync() - Pour les instructions INSERT, UPDATE, DELETE et DDL
  • ExecuteScalarAsync() - Renvoie la première colonne de la première ligne
  • ExecuteReaderAsync() - Renvoie un ClickHouseDataReader permettant de parcourir les résultats

Utilisation de ClickHouseDataReader

Le 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 ClickHouseClient ou ClickHouseConnection.
Approches recommandées :
Si vous utilisez un HttpClient ou un HttpClientFactory personnalisé, assurez-vous que PooledConnectionIdleTimeout est défini sur une valeur inférieure au keep_alive_timeout du serveur, afin d’éviter les erreurs dues à des connexions semi-fermées. La valeur par défaut de keep_alive_timeout pour les déploiements Cloud est de 10 secondes.
Évitez de créer plusieurs instances de ClickHouseClient ou des instances autonomes de ClickHouseConnection sans HttpClient partagé. Chaque instance crée son propre pool de connexions.

Gestion des valeurs DateTime

  1. Utilisez UTC chaque fois que possible. Stockez les horodatages dans des colonnes DateTime('UTC') et utilisez DateTimeKind.Utc dans votre code. Cela élimine toute ambiguïté liée au fuseau horaire.
  2. Utilisez DateTimeOffset pour gérer explicitement le fuseau horaire. Il représente toujours un instant précis et inclut les informations de décalage.
  3. Spécifiez le fuseau horaire dans les annotations de type SQL. Lorsque vous utilisez des paramètres avec des valeurs DateTime Unspecified pour des colonnes non UTC, incluez le fuseau horaire dans le SQL :

Insertions asynchrones

Les insertions asynchrones transfèrent la responsabilité du batching du client vers le serveur. Au lieu d’exiger un batching côté client, le serveur met les données entrantes en mémoire tampon, puis les écrit dans le stockage en fonction de seuils configurables. Cela est utile dans les scénarios à forte concurrence, comme les workloads d’observability où de nombreux agents envoient de petites charges utiles. Activez les insertions asynchrones via CustomSettings ou la chaîne de connexion :
Deux modes (contrôlés par wait_for_async_insert) :
Avec wait_for_async_insert=0, les erreurs n’apparaissent qu’au moment de l’écriture sur disque et ne peuvent pas être rattachées à l’insertion d’origine. Le client ne fournit pas non plus de mécanisme de régulation, ce qui risque de surcharger le serveur.
Paramètres clés :

Sessions

N’activez les sessions que si vous avez besoin de fonctionnalités côté serveur avec état, par exemple :
  • Tables temporaires (CREATE TEMPORARY TABLE)
  • Conservation du contexte de requête d’une instruction à l’autre
  • Paramètres de session (SET max_threads = 4)
Lorsque les sessions sont activées, les requêtes sont sérialisées afin d’éviter l’utilisation concurrente d’une même session. Cela ajoute un surcoût pour les charges de travail qui ne nécessitent pas d’état de session.
Utilisation d’ADO.NET (pour assurer la compatibilité avec les ORM) :

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 :
Pour les colonnes sans fuseau horaire explicite (c.-à-d. 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 :
  1. Utiliser des fuseaux horaires explicites dans vos définitions de colonnes : DateTime('UTC') ou DateTime('Europe/Amsterdam')
  2. 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) : renvoie System.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 de string. 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

Lors de l’insertion de données, le pilote convertit les types .NET vers leurs types ClickHouse correspondants. Les tableaux ci-dessous indiquent quels types .NET sont pris en charge pour chaque type de colonne 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é)
Exemple : DateTime non spécifié (heure locale)
Recommandation : pour un comportement aussi simple et prévisible que possible, utilisez 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

Il existe une différence importante entre la liaison de paramètres HTTP et la copie en masse lors de l’écriture de valeurs DateTime 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) : Accepte string, JsonObject, JsonNode ou tout objet. Toutes les entrées sont sérialisées via System.Text.Json.JsonSerializer et 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’appeler connection.RegisterJsonSerializationType<T>() avant utilisation. L’écriture de valeurs string ou JsonNode dans ce mode lève ArgumentException.
Colonnes JSON typées
Lorsqu’une colonne JSON inclut des indications de type (par ex. 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
Les POCO peuvent être écrits dans des colonnes JSON de deux manières, selon le 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.
La correspondance entre les noms de propriété et les indications de type de colonne est sensible à la casse. Une propriété 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 une ClickHouseJsonSerializationException.
  • 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 types Nullable dans les chemins JSON dynamiques ; les propriétés nulles sans indication sont donc ignorées.
  • Les attributs ClickHouseJsonPath et ClickHouseJsonIgnore sont 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

Les types Nested de ClickHouse (Nested(...)) peuvent être lus et écrits avec la sémantique des tableaux.

Journalisation et diagnostics

Le client .NET ClickHouse s’intègre aux abstractions 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

Vous pouvez configurer les niveaux de journalisation à l’aide de la configuration .NET standard :

Utilisation d’une configuration en mémoire

Vous pouvez également configurer le niveau de verbosité de la journalisation par catégorie dans le code :

Catégories et émetteurs

Le driver utilise des catégories dédiées afin de vous permettre d’ajuster finement les niveaux de journalisation par composant :

Exemple : diagnostic des problèmes de connexion

Les éléments suivants seront consignés :
  • 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

Pour faciliter le diagnostic des problèmes réseau, la bibliothèque du driver inclut un utilitaire qui active le tracing de bas niveau des mécanismes réseau internes de .NET. Pour l’activer, vous devez fournir une instance de LoggerFactory avec le niveau défini sur Trace, et définir EnableDebugMode sur true (ou l’activer manuellement via la classe 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

Le driver intègre une prise en charge native du tracing distribué avec OpenTelemetry via l’API .NET 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

Dans les applications ASP.NET Core, ajoutez l’ActivitySource du driver ClickHouse à votre configuration OpenTelemetry :
Pour les applications en ligne de commande, les tests ou la configuration manuelle :

Attributs des spans

Chaque span inclut les attributs de base de données standard d’OpenTelemetry, ainsi que des statistiques de requête propres à ClickHouse utiles pour le débogage.

Options de configuration

Contrôlez le comportement du tracing à l’aide de ClickHouseDiagnosticsOptions :
L’activation de IncludeSqlInActivityTags peut exposer des données sensibles dans vos traces. À utiliser avec prudence dans les environnements de production.

Configuration TLS

Lorsque vous vous connectez à ClickHouse via HTTPS, vous pouvez configurer le comportement de TLS/SSL de plusieurs manières.

Validation personnalisée des certificats

Pour les environnements de production nécessitant une logique de validation des certificats personnalisée, fournissez votre propre 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 AutomaticDecompression si la compression n’est pas désactivée (elle est activée par défaut).
  • Délai d’inactivité : définissez PooledConnectionIdleTimeout sur une valeur inférieure au keep_alive_timeout du serveur (10 secondes pour ClickHouse Cloud) afin d’éviter les erreurs de connexion dues à des connexions semi-ouvertes.

Prise en charge des ORM

Les ORM nécessitent l’API ADO.NET (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

Tous les modes standard de passage des paramètres de Dapper sont pris en charge : Objets anonymes :
Classes POCO :
Dictionnaire :
DynamicParameters (à partir d’un dictionnaire ou d’un objet anonyme) :

Requêtes vers des POCO

Dapper associe les colonnes aux propriétés par leur nom (sans tenir compte de la casse) :

Syntaxe native des paramètres ClickHouse

Lorsque vous avez besoin d’un contrôle explicite des types, utilisez directement dans le SQL la syntaxe {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

L’expansion native de IN dans Dapper fonctionne :
Dapper réécrit cela en 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

Certains types ClickHouse, par exemple ITuple, BigInteger et ClickHouseDecimal, nécessitent l’enregistrement de gestionnaires au démarrage :
Voir l’exemple Dapper pour un exemple d’implémentation d’un type handler.

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.
Les noms des propriétés doivent correspondre exactement aux noms de colonnes de ClickHouse (respect de la casse).

Limitations

Linq2db

Ce pilote est compatible avec linq2db, un ORM léger et un fournisseur LINQ pour .NET. Consultez le site du projet pour une documentation détaillée. Exemple d’utilisation : Créez une DataConnection à l’aide du fournisseur ClickHouse :
Les mappages de tables peuvent être définis à l’aide d’attributs ou de l’API fluide. Si les noms de votre classe et de vos propriétés correspondent exactement aux noms de la table et des colonnes, aucune configuration n’est nécessaire :
Requêtes :
Bulk Copy : Utilisez BulkCopyAsync pour effectuer efficacement des insertions en bloc.

Entity Framework Core

Le fournisseur officiel Entity Framework Core pour ClickHouse. Associez des classes C# à des tables ClickHouse, effectuez des requêtes avec LINQ et insérez des données via SaveChanges — le tout avec les conventions EF Core habituelles.
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

Nécessite .NET 10.0 et EF Core 10.

Démarrage rapide

Définissez votre entité et le 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/Decimal256decimal en .NET est limité à 28–29 chiffres significatifs.

Opérations LINQ prises en charge

Requêtes : 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
Le fournisseur injecte automatiquement 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 :
Lorsque l’opt-out est activé, LEFT JOIN renvoie les valeurs par défaut des colonnes ClickHouse, et la détection par EF des propriétés de navigation basée sur les valeurs nulles ne fonctionne plus comme prévu. Utilisez des comparaisons explicites 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é :
Les entités passent de 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

Pour les chargements à haut débit, utilisez 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 :
L’entrée peut être n’importe quel 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 AddedUnchanged.

Énumérations

Les colonnes ClickHouse 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

Le système 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é :
Classe de convertisseur réutilisable :

Annotations de type de colonne

Pour les types scalaires comme 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) :
Utilisation de l’API fluide dans OnModelCreating :
Les wrappers imbriqués comme 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

Dans .NET, les colonnes ClickHouse 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() :
Lors de la lecture, la valeur est automatiquement désérialisée dans le type .NET correspondant au discriminateur stocké (par ex. string, ulong, ulong[]).

Colonnes JSON

Le fournisseur prend en charge le type de colonne Json de ClickHouse, qu’il associe à System.Text.Json.Nodes.JsonNode (par défaut) ou à string (via un ValueConverter automatique) :
La lecture et l’écriture du JSON s’effectuent via SaveChanges et BulkInsertAsync :
Si vous préférez des chaînes JSON brutes, mappez la propriété en string avec un type de colonne Json — le fournisseur applique automatiquement un ValueConverter :
  • Pas de traduction des chemins JSONentity.Data["name"] dans LINQ n’est pas converti en syntaxe SQL ClickHouse data.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 via JsonNode, utilisez GetValue<long>() plutôt que GetValue<int>().

Moteurs de table

Configurez les moteurs de table ClickHouse et les clauses propres à chaque moteur à l’aide de l’API fluide 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é.
Familles de moteurs prises en charge : 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(...):
Les index standard (non-skipping) sont ignorés sans avertissement, car ClickHouse n’a pas d’équivalent. Les index uniques provoquent une exception, car ClickHouse ne garantit pas l’unicité.

Migrations

Processus standard des migrations EF Core :
Opérations prises en charge :

Limitations des migrations

Au-delà des migrations, le fournisseur ne prend pas encore en charge :
  • UPDATE / DELETE
  • Transactions : BeginTransaction est 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 ClickHouse data.key. Filtrez sur des colonnes non JSON et inspectez le JSON en mémoire.

Limites

Colonnes de type AggregateFunction

Les colonnes de type AggregateFunction(...) ne peuvent pas être interrogées ni faire l’objet d’une insertion directe. Pour insérer :
Pour sélectionner :

Dernière modification le 1 juillet 2026