Problem Description
When using a Dapper parameter in an SQL WHERE-clause, the parameter appears to be case sensitive. However, when I replace the Dapper parameter with a string literal, the WHERE-clause is no longer case sensitive. I have created a simple ASP.NET Core recipe example web API to help illustrate the problem.
In this recipe example, I am using a PostgreSQL database and want to query a recipe table to get a recipe by name. I have made the name column of type citext, which is a case-insensitive string type.
Database Table
A description of the recipe table:
+-------------+--------+-----------+----------+--------------------+
| Column | Type | Collation | Nullable | Default |
+-------------+--------+-----------+----------+--------------------+
| recipe_id | uuid | | not null | uuid_generate_v4() |
| name | citext | | not null | |
| description | text | | | |
+-------------+--------+-----------+----------+--------------------+
The contents of the recipe table are:
+--------------------------------------+--------------------+-----------------------------------------------------------+
| recipe_id | name | description |
+--------------------------------------+--------------------+-----------------------------------------------------------+
| 8f749e7a-e192-48df-91af-f319ab608212 | meatballs | balled up meat |
| f44c696f-a94a-4f17-a387-dd4d42f60ef8 | red beans and rice | yummy new orleans original |
| 82c5911b-feec-4854-9073-6a85ea793dc0 | pasta cereal | couscous and ground meat eaten with a spoon, like cereal! |
+--------------------------------------+--------------------+-----------------------------------------------------------+
Query Method
The RecipeController has a GetByName method that accepts the name parameter as part of the URI path. The GetByName method calls the GetByNameAsync method of the RecipeRepository class, which contains the SQL statement in question:
public async Task<Recipe> GetByNameAsync(string name)
{
string sql = $@"
SELECT *
FROM {nameof(Recipe)}
WHERE {nameof(Recipe)}.{nameof(Recipe.name)} = @{nameof(name)}";
using (IDbConnection connection = Open())
{
IEnumerable<Recipe> recipes = await connection.QueryAsync<Recipe>(sql, new {name});
return recipes.DefaultIfEmpty(new Recipe()).First();
}
}
Query Responses
If I wanted to query the meatballs recipe by name, and set the name parameter equal to "meatballs", I get the following response:
{
"recipe_id": "8f749e7a-e192-48df-91af-f319ab608212",
"name": "meatballs",
"description": "balled up meat"
}
Setting the name parameter equal to "Meatballs", I get the following response:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"traceId": "00-5e4e35d5cfec644fc117eaa96e854854-c0490c8ef510f3b1-00"
}
And finally, if I replace the Dapper name parameter with the string literal "Meatballs":
public async Task<Recipe> GetByNameAsync(string name)
{
string sql = $@"
SELECT *
FROM {nameof(Recipe)}
WHERE {nameof(Recipe)}.{nameof(Recipe.name)} = 'Meatballs'";
using (IDbConnection connection = Open())
{
IEnumerable<Recipe> recipes = await connection.QueryAsync<Recipe>(sql, new {name});
return recipes.DefaultIfEmpty(new Recipe()).First();
}
}
I get the following response:
{
"recipe_id": "8f749e7a-e192-48df-91af-f319ab608212",
"name": "meatballs",
"description": "balled up meat"
}
Why is this Dapper parameter forcing case-sensitivity? And how can I get around this?