C# Dapper query using WHERE IN - c#

I am trying to perform a dapper query like this:
string query = "select * from MyTable where someNumber in #Nums;";
...
connection.Query<ReturnObj>(query, new {Nums = nums})
And I am getting a MySql syntax error if nums is empty. It looks like Dapper changes the query to look like this: WHERE 1 = 0) so I am guessing it the left ( is missing, which is causing the syntax error. Yes, I realize I could just check if the collection is empty before executing the query, but I would rather not if I don't have to.

This is a bug in Dapper where it creates a SQL statement that is invalid for MySQL Server 5.6 (and earlier).
Workarounds:
Upgrade to MySQL Server 5.7 (which accepts the SQL Dapper generates and returns the expected results)
As you said, check if the collection is empty before executing the query
A variant of checking if the collection is empty (that can be useful if you have a complex query, NOT IN, etc.):
var numsSql = nums.Any() ? "#Nums" : "(select null)";
var query = $"select * from MyTable where someNumber in {numsSql};";
conn.Query(query, new { Nums });

Related

SQLite query not executing properly in a WPF project

I'm working on a WPF application and using SQLite database. I can do every CRUD operation with Entity Framework, but in some specific cases I have to use raw SQL queries, and sometimes it's not returning what I need.
Here is a sample code:
using (var db = new DbContext(AppIO.DatabaseFilePath)) {
var key = 12;
string sql = $"SELECT COUNT(*) FROM SomeTable WHERE SomeField={key}";
var result = db.Database.ExecuteSqlCommand(sql);
}
I simplified the example. Here the result, what I got is -1. I copied the sql string value (after it's built) and executed in SQLiteStuido on the same database and it returned the correct value.
The DatabaseFilePath is correct. The connection is set correctly. I'm checking the same databases (in code and in SQLiteStudio). Any other idea?
Try this:
var result = db.Database.SqlQuery<int>(sql).First();
You have to call SqlQuery method and not ExecuteSqlCommand method. Since SqlQuery returns an IEnumerable you have to call Single. This is a the way to retreive scalar values from a query.
using (var db = new DbContext(AppIO.DatabaseFilePath)) {
var key = 12;
string sql = $"SELECT COUNT(*) FROM SomeTable WHERE SomeField={key}";
var result = db.Database.SqlQuery<int>(sql).Single();
}

Dapper Parameter replace not working for Top

This is my sql
var maxLimit =100;
var sql = "Select Top #MaxLimit from Table WHere data =#Id"
conn.Query<Result>(sql, new {
Id = customerId,
MaxLimit = maxLimit
})
But I get a system error
incorrect syntax near #MaxLimit.
Is Dapper not able to parametrize fields like Top, or Fetch?
In SQL Server any top expression other than a numeric constant needs to be in parentheses.
SELECT TOP (#MaxLimit) FROM ...
Newer versions of dapper have literal replacements and they work great in this case:
var sql = "Select Top {=MaxLimit} from Table WHere data = #Id";

executing a complex sql select for postgresql using c# npgsql

I'm trying to execute a query that will get me a value from my postgre database using c# with the npgsql plugin. I got the query from here.
https://dba.stackexchange.com/a/90567
This is the query
string query = String.Format(#"SELECT a.attrelid::regclass::text, a.attname
, CASE a.atttypid
WHEN 'int'::regtype THEN 'serial'
WHEN 'int8'::regtype THEN 'bigserial'
WHEN 'int2'::regtype THEN 'smallserial'
END AS serial_type
FROM pg_attribute a
JOIN pg_constraint c ON c.conrelid = a.attrelid
AND c.conkey[1] = a.attnum
JOIN pg_attrdef ad ON ad.adrelid = a.attrelid
AND ad.adnum = a.attnum
WHERE a.attrelid = '""public.{0}""'::regclass
AND a.attnum > 0
AND NOT a.attisdropped
AND a.atttypid = ANY('{int,int8,int2}'::regtype[])
AND array_length(c.conkey, 1) = 1
AND ad.adsrc = 'nextval('''
|| (pg_get_serial_sequence (a.attrelid::regclass::text, a.attname))::regclass
|| '''::regclass)'; ", record);
It's giving me a
Input string was not in a correct format.
When it goes through that variable. I only have 1 variable and that's the {0}, but I don't know why it's yelling at me with that.
EDIT:
Btw, the double quotes(") are needed because it is created using entity framework and that's just how it works when you execute the query on pgAdminIII. All the tables needs to be inside them.

Customizing SQL with Dapper Extensions

I'm using Dapper Extensions for some of my types and it works really well for most use cases. I've run into a case where I have a many-many relationship, and I want to do something like:-
SELECT id,a,b,c FROM Foo WHERE Foo.id in (SELECT foo_id FROM foo-bar WHERE bar-id=#bar_id)
Obviously Dapper Extensions can handle "SELECT id,a,b,c FROM Foo" but not the latter part. I could do a select to get the list of Foo id's I want, and then pass that to Dapper Extensions but that's less efficient.
The part I can't do with plain Dapper is get the SELECT column list automatically, so what I'd really like is a way to:-
Get the SELECT column list from Dapper Extension's internal mechanisms
Get the basic "SELECT id,a,b,c FROM Foo" from Dapper Extension's internal mechanisms
Hook Dapper Extensions Get code so that I can add a custom WHERE clause
I've looked at the code, but I can't spot how to do any of these things. Can anyone help? I've worked around by using plain Dapper and "SELECT * ..." at the moment, but I'm sure there's a better way.
Here is another option:
You can create a View:
select * from Foo
join FooBar b
on a.foo_id = b.foo_id
Then use predicates to select with any where clause:
using (SqlConnection cn = new SqlConnection(_connectionString))
{
cn.Open();
var predicate = Predicates.Field<Foo>(f => f.foo_id, Operator.Eq, 1);
IEnumerable<Foo> list = cn.GetList<Foo>(predicate);
cn.Close();
}
Generated SQL should look something like:
SELECT
[Foo].[foo_id]
, [Foo].[...]
, [Foo].[...]
, [Foo].[...]
, [Foo].[...]
FROM [ViewName]
WHERE ([ViewName].[foo_id] = #foo_id_0)
I did not know this was not supported back in 2012. So about 1.7K views in two years and not much exposure. But in case someone new to Dapper landed here and wondering if it works, the answer is, it is working. Using the latest version of, as of this writing, Dapper v1.42 from nuget:
var sql = "SELECT id,a,b,c FROM Foo WHERE Foo.id in (
SELECT foo_id FROM foo-bar WHERE bar-id=#bar_id)"
using (var cn = new SqlConnection(the_connection_string)) {
cn.Open();
var returnedObject = cn.Query<dynamic>(sql, new { bar_id = some_value });
}

Dapper LIKE query for MySql safe against Sql Injection?

Is this query safe against sql injection in combination with Dapper?
If not, what would be the correct way to write it under MySql?
Or is there a better version without using concat?
string sql = "SELECT * from user_profile WHERE FirstName LIKE CONCAT("%",#name,"%");"
var result = connection.query<profile>(sql, new {name});
There isn't a problem with that code, but another approach is to perform the the concat at the caller, i.e.
const string sql = "SELECT * from user_profile WHERE FirstName LIKE #name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});
This is safe because you are not building SQL dynamically at all. Name is just a normal parameter. Actually, it has nothing to do with Dapper.
Using a string concat here is the right choice. Alternatively you could use the SUBSTRING_INDEX function.

Categories

Resources