The Hidden Gap Between .NET Strings and SQL Server Types
Dapper is lauded for its simplicity. It gets out of your way, letting you write SQL and map results to objects with minimal ceremony. This directness is a key reason for its popularity in backend systems. However, this lean approach can sometimes obscure critical details, particularly around parameter metadata. A prime example is the handling of string types.
In .NET, we work with a generic string type. But SQL Server is far more granular. It distinguishes between varchar, nvarchar, char, nchar, and requires specific sizes and other metadata for each. This disconnect between the application's abstract string and the database's precise type is a common source of subtle bugs and performance issues. When a .NET string is sent to SQL Server, Dapper makes an educated guess about the appropriate SQL type, but this guess isn't always correct, especially with varying string lengths or character encodings.
This gap in type specificity is precisely what led Rodri Oliveira to develop Dapper.TypedParameters. The library aims to bridge this divide by allowing developers to explicitly define the SQL Server data type for each parameter, ensuring that what reaches the database is exactly what the developer intended.

Explicit Typing for Robust Data Handling
Dapper.TypedParameters introduces a fluent API for defining parameter types. Instead of relying on Dapper's default type inference, developers can now specify SQL Server types like NVARCHAR(MAX), VARCHAR(50), or even DECIMAL(18, 2) directly within their C# code. This explicit mapping provides several benefits:
- Prevents Type Mismatches: Eliminates runtime errors caused by unexpected type conversions or data truncation when passing parameters to SQL Server.
- Improves Performance: By specifying precise types and lengths, developers can help SQL Server optimize query plans more effectively. Incorrect type inference can sometimes lead to implicit conversions that hinder performance.
- Enhances Code Readability: The explicit type definitions serve as clear documentation within the code itself, making it easier for other developers (or your future self) to understand the expected data types for database operations.
- Handles Large Objects (LOBs): Explicitly defining parameters as
NVARCHAR(MAX)orVARBINARY(MAX)ensures that large text or binary data is handled correctly without unexpected truncation.
Consider a scenario where an application stores user-generated content that might exceed the default VARCHAR(8000) limit often inferred. Without explicit typing, such data could be silently truncated, leading to data loss. With Dapper.TypedParameters, you can specify NVARCHAR(MAX), ensuring the entire content is preserved.
How Dapper.TypedParameters Works
The library extends Dapper's existing parameter handling. Developers create an instance of TypedParameters and then chain calls to define each parameter and its corresponding SQL Server type. For example:
var parameters = new TypedParameters()
.AddNVarChar("Name", "John Doe", 100)
.AddVarChar("Status", "Active", 50)
.AddDecimal("Amount", 123.45m, 10, 2);
connection.Execute("usp_UpdateRecord", parameters, commandType: CommandType.StoredProcedure);
This syntax is clean and mirrors Dapper's own parameter object creation, making the transition straightforward. The library handles the underlying creation of SqlParameter objects with the specified types, sizes, and precision, ensuring that the correct metadata is sent to SQL Server.
The library supports a wide range of SQL Server data types, including:
- String types:
VARCHAR,NVARCHAR,CHAR,NCHARwith configurable lengths. - Numeric types:
INT,BIGINT,DECIMAL,NUMERIC,FLOAT,REALwith configurable precision and scale. - Date and Time types:
DATETIME2,DATE,TIME. - Large Object types:
VARCHAR(MAX),NVARCHAR(MAX),VARBINARY(MAX).
Support for other types like BIT, UNIQUEIDENTIFIER, and spatial types is also available, aiming for comprehensive coverage of common SQL Server needs.
Beyond Strings: Addressing Other Type Nuances
While string handling is a primary driver, Dapper.TypedParameters also addresses other type-related subtleties. For instance, numeric types in SQL Server have specific precision and scale requirements. Passing a .NET decimal without specifying these can lead to unexpected rounding or errors if the database column has stricter constraints. Similarly, date/time types can have subtle differences in precision and range between .NET and SQL Server versions. By allowing explicit definition, the library ensures that these fine-grained details are managed correctly.
This library is particularly valuable in enterprise environments where database schemas are rigorously defined and enforced. It provides a safety net for developers, preventing common errors that might slip through during development and only manifest in production. It encourages a more disciplined approach to data interaction, aligning application code more closely with database realities.
The Unanswered Question: Wider Adoption and Standardisation
What remains to be seen is whether a pattern like this will eventually influence ORMs or data access libraries more broadly. Dapper's strength has always been its minimalist design. Introducing explicit type mapping, while beneficial, adds a layer of complexity. Will other micro-ORMs adopt similar explicit typing features, or will this remain a specialized solution for developers who encounter specific SQL Server type-related challenges?
For developers working with SQL Server and Dapper, Dapper.TypedParameters offers a clear path to more robust and predictable data interactions. It transforms potential runtime surprises into compile-time or explicit code decisions, making database interactions more reliable.
