DapperLib / DapperLib/Dapper

implicit type cast operators to avoid needing to explicitly use DynamicParameters

Open
#2,055 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
18.4k
Forks
3.7k
Avg merge
5h 8m
Merged PRs (30d)
1

Description

tl;dr;
cn.Execute("Pass @Param as VARCHAR instead of NVARCHAR", new {Param = (AnsiString)"MyString"});

I frequently use anonymous types to call Dapper with parameterized SQL statements. As SQL Server uses NVARCHAR in precedence to VARCHAR, I have to explicitly set the DbType to DbType.AnsiString in order to get it to pass a VARCHAR instead of an NVARCHAR; when I fail to do this, SQL Server will ignore indexes on the VARCHAR column. I've started using this technique to be able to continue to pass anonymous types, while getting the correct parameter type that utilizes the index. I searched the repo and the web for this, and don't see it anywhere and I felt this could be a useful pattern for "fire and forget" passing of anonymous types while passing strings as VARCHAR instead of NVARCHAR.

`
SqlMapper.AddTypeHandler(new AnsiStringTypeHandler());
//...
public class AnsiString
{
string _value;
private AnsiString(string value)
{
_value = value;
}

public override bool Equals(object? obj)
{
    return _value == null ? false : _value.Equals(obj);
}

public override int GetHashCode() => (_value != null ? _value.GetHashCode() : 0);

public static implicit operator string(AnsiString value) => value._value;
public static implicit operator AnsiString(string value) => new AnsiString(value);

}

public class AnsiStringTypeHandler : SqlMapper.TypeHandler
{
public override AnsiString? Parse(object value)
{
return (AnsiString?)value;
}

public override void SetValue(IDbDataParameter parameter, AnsiString? value)
{
    parameter.Value = value != null ? (string)value : DBNull.Value;
    parameter.DbType = DbType.AnsiString;
    parameter.Size = DbString.DefaultLength;
}

}
//Usage:
using (var cn = new SqlConnection(connectionString))
{
await cn.OpenAsync();
await cn.ExecuteAsync(@"CREATE TABLE #Test (Col1 NVARCHAR(20), Col2 VARCHAR(20))

        INSERT #Test
        VALUES (@A, @B)
        ,      (@C, @D)", new { A = "TestA", B = (AnsiString)"TestB", C = "TestC", D = "TestD" });
    }

`

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue centers on anonymous-object parameter binding and the SqlMapper.TypeHandler API; start by tracing how Dapper infers DbType for string parameters and compare it with the shown AnsiStringTypeHandler. Done means an anonymous value cast to AnsiString reaches SQL Server as DbType.AnsiString without requiring DynamicParameters, with coverage for the demonstrated behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sql
Domain
backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.