Search code examples
postgresqldappernpgsql

Using Dapper and Postgresql - citext data type


I'm not sure if there is a way to support this, but I'm having trouble getting Dapper to map string parameter values to the Postgresql citext data type as it seems to be using the text type.

In particular, I'm trying to call a function that takes in citext parameters - the error I get back is:

var c = ConnectionManager<T>.Open();
string sql = @"select * from ""dbo"".""MyFunction""(@schemaName, @tableName);";
var param = new
{
    schemaName = schema,
    tableName = table
};

string insecureSalt = c.QueryMultiple(sql, param).Read<string>().FirstOrDefault();
ConnectionManager<T>.Close(c);

Error: Npgsql.PostgresException: 42883: function dbo.MyFunction(text, text) does not exist.

The signature that would match is function dbo.MyFunction(citext, citext) so clearly it can't find it using the default mapping.

According to Npgsql - http://www.npgsql.org/doc/types.html I need to be able to specify NpgsqlDbType.Citext as the type but I can't find a way to do this using Dapper.

Solved thanks to answer from Shay, complete solution here:

var c = ConnectionManager<T>.Open();
string sql = @"select * from ""dbo"".""MyFunction""(@schemaName, @tableName);";
var param = new
{
    schemaName = new CitextParameter(schema),
    tableName = new CitextParameter(table)
};

string insecureSalt = c.QueryMultiple(sql, param).Read<string>().FirstOrDefault();
ConnectionManager<T>.Close(c);

public class CitextParameter : SqlMapper.ICustomQueryParameter
{
    readonly string _value;

    public CitextParameter(string value)
    {
        _value = value;
    }

    public void AddParameter(IDbCommand command, string name)
    {
        command.Parameters.Add(new NpgsqlParameter
        {
            ParameterName = name,
            NpgsqlDbType = NpgsqlDbType.Citext,
            Value = _value
        });
    }
}

Solution

  • You probably need to create create a CitextParameter which extends ICustomQueryParameter. This API allows you to pass an arbitrary DbParameter instance to Dapper - in this case it would be an instance of NpgsqlParameter with its NpgsqlDbType set to Citext.

    Something like this should work:

    class CitextParameter : SqlMapper.ICustomQueryParameter
    {
        readonly string _value;
    
        public CitextParameter(string value)
        {
            _value = value;
        }
    
        public void AddParameter(IDbCommand command, string name)
        {
            command.Parameters.Add(new NpgsqlParameter
            {
                ParameterName = name,
                NpgsqlDbType = NpgsqlDbType.Citext,
                Value = _value
            });
        }
    }