This query works; that is, it returns the expected results:
var r = sql.Query<T>("select * from TableName where Name = '" + name + "'");
but, if one of the 'names' values contains an apostrophy (which is true), then an exception is thrown '{"Incorrect syntax near 'Resources'.\r\nUnclosed quotation mark after the character string ''."}' - in an attempt to fix that problem, my query no longer returns any results; but it should.
I've attempted to change the code in a few ways, but no results are returned with either of the following changes:
var r = sql.Query<T>("select * from TableName where Name = '#name'", new { name });
or
var args = new DynamicParameters(name);
var r = sql.Query<T>("select * from TableName where Name = '#name'", args);
or
var args = new DynamicParameters(); args.AddDynamicParams(new { name });
var r = sql.Query<T>("select * from TableName where Name = '#name'", args);
or
var args = new DynamicParameters(); args.Add("#name", name);
var r = sql.Query<T>("select * from TableName where Name = '#name'", args);
This is probably something trivial that I have simply just not yet grasped the concept for ... but I'm at the point of having spent too much time trying to figure it out - hence the question.
Using a parameter is the right way to go. You absolutely don't want to put the value into the query itself as you did in your first snippet. However, you've put the #name in quotes, which means it's being treated as a string literal... it's looking for a name value of exactly #name rather than the value of the #name parameter. You want:
var r = sql.Query<T>("select * from TableName where Name = #name", new { name });
(That's probably the simplest way of passing the parameters, though the other approaches should work too.)
Now I haven't actually used Dapper myself, but that's what I'd expect...
Related
I'm having troubles with my param string on my WHERE clause of my method. I'm trying to do a query like this:
string query = "SELECT * FROM table WHERE Name #Filter OR Email #Filter";
And then inside my switch their cases will be like:
public async Task<List<DTO>>Get(FilterDTO filter)
{
foreach(var f in filter.fields)
{
switch(f.Operator)
{
case 1:
if(f.Value == null)
{
f.Value = "IS NULL";
queryResult = connection.Query<Model>(query, new {Filter = f.Filter});
break;
}
else
goto case 2;
I'm having a lot of troubles with my param string because I cannot see what is failing on debug
Notice my real value name is FilterValue (this code it's a simplification)
I get this error:
Incorrect syntax near #Filter
So I know something is wrong about my param string input but I cannot see what is it
Rewrite the query to:
SELECT * FROM table WHERE (#Filter is null and Email is null or #Filter = Email)
OR (#Filter is null and Name is null or #Filter = Name)
In that case you can set the parameter Filter = null and get the expected result.
Probably Dapper is using this query:
SELECT *
FROM table
WHERE Name = IS NULL OR Email = IS NULL
which is invalid.
First create a profiler to see what query dapper is actually executing on the database (is easier to debug this situations - I recommend MiniProfiler lib).
Second, the IS NULL filter is meant to be on the query string OR use: Name = NULL rather than IS NULL
I don't think you can use parameters from Dapper like this.
To have a valid query you'd need to have
SELECT * FROM table WHERE Name = #Filter OR Email = #Filter;
But that won't work with null.
You actually need to create the query, not just the parameters
const string query = "SELECT * FROM table WHERE Name {0} OR Email {0}";
var result = conn.Query(string.Format(query, filterValue));
Edit:
If you can use Dapper.SqlBuilder you can build the query with Dapper as well.
Something like this:
var sqlBuilder = new SqlBuilder();
string myFilterValue = null;
if (string.IsNullOrEmpty(myFilterValue))
{
sqlBuilder.OrWhere("Name IS NULL").OrWhere("Email IS NULL");
}
else
{
sqlBuilder.OrWhere("Name = #Filter", new { Filter = myFilterValue }).OrWhere("Email = #Filter", new { Filter = myFilterValue });
}
var template = sqlBuilder.AddTemplate("select * from table /**where**/");
using var conn = new SqlConnection("");
var result = conn.Query(template.RawSql, template.Parameters);
I am trying to get indexes fragmentation info from database.
Here the dapper sql query:
var result = await _dbConnection.QueryAsync<IndexFragmentationModel>($#"
select
a.index_id as Id, name as Name, avg_fragmentation_in_percent as FragmentationPercent
from sys.dm_db_index_physical_stats (DB_ID(N'#dbName'), OBJECT_ID(N'#tableName'), null, null, null) as a
join sys.indexes as b on a.object_id = b.object_id and a.index_id = b.index_id;
", new
{
dbName = dbName,
tableName = tableName
});
return result.ToList();
Parameters are not passing the the places where they are expected.
Could anybody please suggest - maybe there is another way to pass them ?
You're using the literal strings "#dbName" and "#tableName", not the parameters' values.
Remove the N' and ' that surround them.
Take this code as an example:
IAmazonSimpleDB client = new AmazonSimpleDBClient(Amazon.RegionEndpoint.USEast1);
SelectResponse response = client.Select(new SelectRequest() {
SelectExpression = "SELECT * FROM `foo` where FooID = '" + id + "'" });
I can rewrite it as such:
IAmazonSimpleDB client = new AmazonSimpleDBClient(Amazon.RegionEndpoint.USEast1);
SelectResponse response = client.Select(new SelectRequest() {
SelectExpression = "SELECT * FROM `foo` where FooID = '{0}'", id });
But from my understanding, that still leaves it vulnerable to injection right?
Is there anything else I can do here? We aren't using SQL so I can't do SQL Parameters.
I usually do a check to see if the id is an integer. That way you will get an exception or a Boolean value if it isn't an int. It will work fine unless you are using GUID values.
var isNumeric = int.TryParse("123", out int n); //Will give a bool
Int32.Parse(yourString); //This will give an exception if it is not an possible integer
If it's anything more than that then you could use a Regex expression to look for strange values and remove characters that shouldn't be there such as spaces. Most SQL injection attacks wont work if there's no spaces... I think. Removing all the spaces is pretty easy and I would assume your ID (even if it is complex) won't include spaces.
string s = " "
string t = s.Replace(" ", ""). //It will be hard to do a sql attack if the spaces are removed.
A little off topic but with C# 6.0 you can format string differentlyl; It's a new feature called "string interpolation" (thanks Etienne de Martel).
$"SELECT * FROM `foo` where FooID = '{id}'"
I am using Entity Framework 4.3, and below is my code (BTW, the RealPrice field of the gift table is of decimal type):
var filters = new StringBuilder();
var parameters = new List<object>();
decimal numRealPrice = 25.00m;
filters.Append("RealPrice = #RealPrice");
var paramRealPrice = new SqlParameter("#RealPrice", SqlDbType.Decimal);
paramRealPrice.Value = numRealPrice;
parameters.Add(numRealPrice);
string sqlStatement = "SELECT * FROM gift WHERE ";
sqlStatement = sqlStatement + filters;
List<OM_Gift_BO> gifts = this.objEntity.ExecuteStoreQuery<OM_Gift_BO>(sqlStatement, parameters.ToArray()).ToList();
//....
And the framework somewhat generated a SQL query(according to Express profiler 2.0):
exec sp_executesql N'SELECT * FROM gift WHERE RealPrice = #RealPrice',N'#p0 decimal(4,2)',#p0=25.00
go
I have no idea where does the name 'p0' come from, however, since it is different from RealPrice, I got an exception saying:
Must declare the scalar variable "#RealPrice".
Well, this method works OK with string type parameters.
Any help is appreciated, thanks in advance.
The problem seems to be your assigning numRealPrice directly to your parameters and passing that directly to ExecuteStoreQuery
Replace
parameters.Add(numRealPrice);
With
parameters.Add(paramRealPrice);
Additionally I'm not sure if its of any value, as it depends on what your trying to achieve, however you could probably shorten your code as follows
var statement = "SELECT * FROM gift WHERE RealPrice = {0}";
var gifts = context.ExecuteStoreQuery<OM_Gift_BO>(statment, numRealPrice).ToList();
The method takes a string for the query, and an array of Object [] for the parameters, presumably to avoid SQL Injection.
However nowhere on earth is it documented what you should put into the object array.
There is another question on SO that asks this exact same thing, but the accepted answer doesn't work: When using DbSet<T>.SqlQuery(), how to use named parameters?
I've tried all forms of parameter replacement I can think of and all of them throw an exception. Any ideas?
Would that it were as simple as:
SqlQuery("SELECT * FROM #table", "Users")
Edit: Here are some things I've tried (Exception is an SqlException):
var result = context.Users.SqlQuery<T>("SELECT * FROM #p0 WHERE #p1 = '#p2'",
new SqlParameter("p0", tableName),
new SqlParameter("p1", propertyName),
new SqlParameter("p2", searchQuery));
This gives Must declare the table variable "#p0".
var result = context.Users.SqlQuery<T>("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, propertyName, searchQuery);
This gives Must declare the table variable "#p0".
There is nothing wrong with your query syntax or how do you created and passed in the SqlParameter objects.
Your problem is that you try to use a variable as the table name, what you cannot do (see: Must declare the table variable #table), so you need to manually "template" the table name in your query:
Something like.
var result = context.Users.SqlQuery<T>(
"SELECT * FROM " + tableName + " WHERE #p0 = '#p1'",
new SqlParameter("p0", propertyName),
new SqlParameter("p1", searchQuery));