You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/integrations/language-clients/csharp.md
+131Lines changed: 131 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,6 +103,7 @@ Below is a full list of all the settings, their default values, and their effect
103
103
| UseCustomDecimals |`bool`|`true`|`UseCustomDecimals`| Use `ClickHouseDecimal` for arbitrary precision; if false, uses .NET `decimal` (128-bit limit) |
104
104
| ReadStringsAsByteArrays |`bool`|`false`|`ReadStringsAsByteArrays`| Read `String` and `FixedString` columns as `byte[]` instead of `string`; useful for binary data |
105
105
| UseFormDataParameters |`bool`|`false`|`UseFormDataParameters`| Send parameters as form data instead of URL query string |
106
+
| ParameterTypeResolver |`IParameterTypeResolver`|`null`| — | Custom resolver for `@`-style parameter type mapping; see [Custom parameter type mapping](#parameter-type-mapping)|
106
107
| JsonReadMode |`JsonReadMode`|`Binary`|`JsonReadMode`| How JSON data is returned: `Binary` (returns `JsonObject`) or `String` (returns raw JSON string) |
107
108
| JsonWriteMode |`JsonWriteMode`|`String`|`JsonWriteMode`| How JSON data is sent: `String` (serializes via `JsonSerializer`, accepts all inputs) or `Binary` (registered POCOs only with type hints) |
| UseSession |`bool?`| Override session behavior for this query |
186
187
| SessionId |`string`| Session ID for this query (requires `UseSession = true`) |
187
188
| BearerToken |`string`| Override authentication token for this query |
189
+
| ParameterTypeResolver |`IParameterTypeResolver`| Override client-level resolver for `@`-style parameter type mapping; see [Custom parameter type mapping](#parameter-type-mapping)|
188
190
| MaxExecutionTime |`TimeSpan?`| Server-side query timeout (passed as `max_execution_time` setting); server cancels query if exceeded |
189
191
190
192
**Example:**
@@ -430,6 +432,74 @@ var options = new InsertOptions
430
432
* Use `RowBinaryFormat.RowBinaryWithDefaults` in `InsertOptions.Format` if you want the server to apply DEFAULT values for columns not provided.
431
433
:::
432
434
435
+
#### POCO inserts {#poco-insert}
436
+
437
+
Instead of constructing `object[]` arrays, you can insert strongly-typed POCO objects directly. Register the type once, then pass `IEnumerable<T>`:
438
+
439
+
```csharp
440
+
// Define a POCO matching your table columns
441
+
publicclassSensorReading
442
+
{
443
+
publiculongId { get; set; }
444
+
publicstringSensorName { get; set; }
445
+
publicdoubleValue { get; set; }
446
+
publicDateTimeTimestamp { get; set; }
447
+
}
448
+
449
+
// Register the type (once per client lifetime)
450
+
client.RegisterBinaryInsertType<SensorReading>();
451
+
452
+
// Insert directly — column names are derived from property names
By default, all public readable properties are mapped to columns using strict case-sensitive name matching. You can customize the mapping with attributes:
466
+
467
+
```csharp
468
+
publicclassEvent
469
+
{
470
+
[ClickHouseColumn(Name="event_id")] // Map to a differently-named column
471
+
publiculongId { get; set; }
472
+
473
+
[ClickHouseColumn(Type="LowCardinality(String)")] // Explicit ClickHouse type
474
+
publicstringCategory { get; set; }
475
+
476
+
publicstringPayload { get; set; }
477
+
478
+
[ClickHouseNotMapped] // Exclude from insert
479
+
publicstringInternalTag { get; set; }
480
+
}
481
+
```
482
+
483
+
| Attribute | Purpose |
484
+
|-----------|---------|
485
+
|`[ClickHouseColumn(Name = "...")]`| Override the target column name |
486
+
|`[ClickHouseColumn(Type = "...")]`| Declare the ClickHouse type explicitly |
487
+
|`[ClickHouseNotMapped]`| Exclude the property from the insert |
488
+
489
+
When **all** mapped properties specify an explicit `Type`, the schema probe query is skipped entirely. When only some properties have explicit types, the driver falls back to the schema probe for the full column set.
490
+
491
+
`InsertBinaryAsync<T>` supports the same `InsertOptions` (batching, parallelism, schema caching) as the `object[]` overload.
492
+
493
+
:::note
494
+
Unlike the `object[]` overload, `InsertBinaryAsync<T>` does not accept an explicit column list. Columns are determined by the registered type's mapped properties. To control which columns are inserted, use `[ClickHouseNotMapped]` to exclude properties or `[ClickHouseColumn(Name = "...")]` to rename them.
495
+
496
+
If `ColumnTypes` is set in `InsertOptions`, they will override the POCO attributes.
POCO inserts work seamlessly when columns are added to the target table after the type is registered. Because the driver only inserts the columns mapped by the POCO, any new columns with `DEFAULT` (or other default expressions) are filled in by the server automatically. No code changes or re-registration are needed.
502
+
433
503
---
434
504
435
505
### Reading data {#reading-data}
@@ -504,6 +574,67 @@ If you're specifying a custom `QueryId`, ensure it is unique for every call. A r
504
574
505
575
---
506
576
577
+
### Custom parameter type mapping {#parameter-type-mapping}
578
+
579
+
When using `@`-style parameters (e.g., `WHERE id = @id`), the driver automatically infers the ClickHouse type from the .NET value type. For example, `int` maps to `Int32`, and `DateTime` maps to `DateTime`.
580
+
581
+
To override these defaults, set `ParameterTypeResolver` on `ClickHouseClientSettings`. This is useful when you want all `DateTime` parameters to use `DateTime64(3)` for millisecond precision, or all decimals to use a specific scale, without setting `ClickHouseType` on every individual parameter.
582
+
583
+
**Using `DictionaryParameterTypeResolver` for simple type mappings:**
**Custom `IParameterTypeResolver` for advanced scenarios:**
606
+
607
+
For value-aware or name-based resolution, implement the `IParameterTypeResolver` interface directly. Return `null` to fall through to the default inference:
You can also set a resolver for a single query via `QueryOptions.ParameterTypeResolver`. When set, it takes precedence over the client-level resolver.
624
+
625
+
**Type resolution precedence:**
626
+
627
+
The resolver is one step in a precedence chain. From highest to lowest priority:
628
+
629
+
1. Explicit `ClickHouseType` set on the parameter
630
+
2. SQL type hint from `{name:Type}` syntax in the query
631
+
3.`IParameterTypeResolver` (from `QueryOptions.ParameterTypeResolver`, falling back to `ClickHouseClientSettings.ParameterTypeResolver`)
632
+
4. Built-in type inference (`TypeConverter.ToClickHouseType`)
633
+
634
+
The resolver also works with the ADO.NET `ClickHouseConnection` path — the settings are inherited by connections created from the client.
635
+
636
+
---
637
+
507
638
### Raw streaming {#raw-streaming}
508
639
509
640
Use `ExecuteRawResultAsync` to stream query results in a specific format directly, bypassing the data reader. This is useful for exporting data to files or passing through to other systems:
0 commit comments