Is there a built-in class in the .Net framework that can be used to denote an AnsiString?

StackOverflow https://stackoverflow.com/questions/6069021

  •  07-09-2020
  •  | 
  •  

Question

For dapper I need to build support for passing in AnsiString params.

Databases have both unicode and non-unicode strings, picking the right parameter type is sometimes crucial.

DbType.String vs DbType.AnsiString for a particular param can heavily effect perf.

In dapper we pass in parameters dynamically, Eg:

Query<User>("select * from Users where Name=@Name", new {Name = "name"});

I have an internal map that says that if I see typeof(String) I know to pass in the param as a DbType.String

However, I would like my users to be able to denote that the string should be an AnsiString. Attributes are not supported for anonymous classes, so I need a distinct type for this.

Clearly I can invent one:

public class AnsiString 
{
    private readonly string str;
    public AnsiString(string str)
    {
        this.str = str;
    }

    public String Value { get { return str; } }
}

Which would give me the clean API:

Query<User>("select * from Users where Name=@Name", 
   new {Name = new AnsiString("name")});

However, why invent one if such a class exists in System.Data or the BCL.

Is there a type somewhere in the BCL or System.Data I could use as a container for AnsiString, with similar semantics to the sample above?

Was it helpful?

Solution

There is not such class in the BCL or System.Data, you will have to roll your own.

We went with a custom type to provide more fine-grained customn in the end; this test shows typical usage:

public void TestDbString()
{
    var obj = connection.Query("select datalength(@a) as a, datalength(@b) as b, datalength(@c) as c, datalength(@d) as d, datalength(@e) as e, datalength(@f) as f",
        new
        {
            a = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = true },
            b = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = false },
            c = new DbString { Value = "abcde", IsFixedLength = false, Length = 10, IsAnsi = true },
            d = new DbString { Value = "abcde", IsFixedLength = false, Length = 10, IsAnsi = false },
            e = new DbString { Value = "abcde", IsAnsi = true },
            f = new DbString { Value = "abcde", IsAnsi = false },
        }).First();
    ((int)obj.a).IsEqualTo(10);
    ((int)obj.b).IsEqualTo(20);
    ((int)obj.c).IsEqualTo(5);
    ((int)obj.d).IsEqualTo(10);
    ((int)obj.e).IsEqualTo(5);
    ((int)obj.f).IsEqualTo(10);
}

So; it supports:

  • ansi vs unicode
  • fixed vs dynamic length
  • in the case of dynamic length, explict vs implicit (4000 if the length is <= 4000; "max" otherwise - this keeps the number of query-plans sane)

The type is available inside dapper.

OTHER TIPS

I guess you can use string for DbType.String and char[] for DbType.AnsiString.

It will look very similar to your current code:

Query<User>("select * from Users where Name=@Name", new {Name = "name".ToCharArray()});

Or if you wan use your AnsiString, you can create extension method .ToAnsiString():

public static AnsiString( this string s ) { return new AnsiString(s); }
Query<User>("select * from Users where Name=@Name", new {Name = "name".ToAnsiString()});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top