I'm having troubles trying to execute a SQL query with repeated parameters using entity framework.
The query is a keyword search, that looks in different tables, therefore using the same parameter many times. I'm using LIKE statements (yes, I know I should be using FULLTEXTSEARCH, but I don't have time for that right now).
I've tried all the syntax explained here: How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5 and none of them make the query work (I get zero returned rows).
I even tried building a string array in runtime, with length equal to the number of times the parameter repeats in the query, and then populating all the elements of the array with the keyword search term. Then I passed that as the object[] parameters. Didn't work either.
The only thing that works is to make a search&replace that is obviously a bad idea because the parameter comes from a text input, and I'll be vulnerable to SQL injection attacks.
The working code (vulnerable to SQL injection attacks, but the query returns rows):
//not the real query, but just for you to have an idea
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE '%{0}%' " +
"OR UPPER(Field2) LIKE '%{0}%'";
//keywordSearchTerms is NOT sanitized
query = query.Replace("{0}", keywordSearchTerms.ToUpper());
List<ProjectViewModel> list = null;
using (var context = new MyContext())
{
list = context.Database.SqlQuery<ProjectViewModel>(query, new object[] { }).ToList();
}
return list;
I'm using ASP.NET MVC 4, .NET 4.5, SQL Server 2008 and Entity Framework 5.
Any thoughts on how to make the SQLQuery<> method populate all the occurrences of the parameter in the query string? Thank you very much for your time.
Try this:
string query =
#"SELECT Field1,
Field2
FROM Table1
WHERE UPPER(Field1) LIKE '%' + #searchTerm + '%'
OR UPPER(Field2) LIKE '%' + #searchTerm + '%'";
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", searchTerm)).ToList();
You can use parameters in your query. Something like this
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE #searchTerm" +
"OR UPPER(Field2) LIKE #searchTerm";
string search= string.Format("%{0}%", keywordSearchTerms);
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", search)).ToList();
how about try this
string query =
string.Format("SELECT Field1, Field2 FROM Table1 WHERE UPPER(Field1) LIKE '%{0}%'
OR UPPER(Field2) LIKE '%{0}%'",keywordSearchTerms.ToUpper());
context. Database.SqlQuery< ProjectViewModel >(query)
Related
I have a table with a lot of employees in it, every person has a Name column with their full name.
I then want to do a query similar to this when searching for people:
SELECT * FROM Employees WHERE Name LIKE '%' + #value1 + '%' AND Name LIKE '%' + #value2 +'%' AND so forth...
for an arbitrary array of values.
My Dapper code would look something like this:
public IEnumerable<Employee> Search(string[] words)
{
using var connection = CreateConnection();
connection.Query<Employee>("SELECT * etc.", words);
}
Is there ANY way to do this with SQL without resorting to string concatenation, and the risk of SQL Injection attacks that follows?
Caveat: I don't know how Dapper actually passes an array to the query, which limits my creative ideas for working around this :-D
And also: Changing the Table structure is, unfortunately, out of the question. And I'd rather avoid fetching every single person into .Net memory and doing the filtering there.
Is there ANY way to do this with SQL without resorting to string concatenation, and the risk of SQL Injection attacks that follows?
Because the set of where conditions is not fixed you will need to build the query dynamically. But that does not mean you cannot parameterise the query, you just build the parameter list alongside building the query. Each time a word from the list add to the condition and add a parameter.
As Dapper doesn't directly include anything that takes a collection of DbParameter, consider using ADO.NET to get an IDataReader and then Dappter's
IEnumerable<T> Parse<T>(this IDataReader reader)
for the mapping.
Such a builder would be very roughly
var n = 0;
for (criterion in cirteria) {
var cond = $"{crition.column} like #p{n}";
var p = new SqlPatameter($"#p{n}", $"%{crition.value}%";
conditions.Add(cond);
cmd.Parameters.Add(p);
}
var sql = "select whetever from table where " + String.Join(" and ", conditions);
cmd.CommandText = sql;
var reader = await cmd.ExecuteReaderAsync();
var res = reader.Parse<TResult>();
For performance reasons, it's much better to do this as a set-based operation.
You can pass through a datatable as a Table-Value Parameter, then join on that with LIKE as the condition. In this case you want all values to match, so you need a little bit of relational division.
First create your table type:
CREATE TYPE dbo.StringList AS TABLE (str varchar(100) NOT NULL);
Your SQL is as follows:
SELECT *
FROM Employees e
WHERE NOT EXISTS (SELECT 1
FROM #words w
WHERE e.Name NOT LIKE '%' + w.str + '%' ESCAPE '/' -- if you want to escape wildcards you need to add ESCAPE
);
Then you pass through the list as follows:
public IEnumerable<Employee> Search(string[] words)
{
var table = new DataTable{ Columns = {
{"str", typeof(string)},
} };
foreach (var word in words)
table.Rows.Add(SqlLikeEscape(word)); // make a function that escapes wildcards
using var connection = CreateConnection();
return connection.Query<Employee>(yourQueryHere, new
{
words = table.AsTableValuedParameter("dbo.StringList"),
});
}
I know a lot of questions exists about this topic. But i tried everything and nothing worked. As I mentioned in the title, i'm trying to change my unsafe query into a safer one.
I think the problem are the points. My goal is to insert the month and the year into the query. And both should be separated by points.
Just something like this: " .08.2017 "
The old query which worked
string Query = #"select id from ferien WHERE Datum LIKE '%." + monat + "." + jahr + "'";
The new query which doesn't work
String Query = #"select id from ferien WHERE Datum LIKE '%. #monat . #jahr'";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#monat", monat);
command.Parameters.Add("#jahr", jahr);
command.ExecuteNonQuery();
}
I'm using a sqlite db.
I'm thankful for any advice or solution.
Edit
It doesn't give me any errors. While debugging it runs trough like normal. It just acts like it found nothing in the db.
Fixing your current approach:
You'd have to concat the parameter with the fixed part of the query, so depending on your database, it would be something like
select id from ferien WHERE Datum LIKE '%.' || #monat || '.' || #jahr
or
select id from ferien WHERE Datum LIKE CONCAT('%.', #monat, '.', #jahr)
I think the first one using the common || SQL concatenation operator works in SQLite as well. Note that the common + operator typically doesn't work for string concatenation in SQL.
The whole code would become
String Query = #"select id from ferien WHERE Datum LIKE '%' || #monat || '.' || #jahr";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#monat", monat);
command.Parameters.Add("#jahr", jahr);
command.ExecuteNonQuery();
}
(Better?) between:
That aside, it would be even better if you have an actual date in your database, and you would use that in your query, so it would look like:
select id from ferien WHERE Datum BETWEEN "2017-08-01" AND "2017-09-01"
See also SQLite: SQL Select between dates
You're not using the parameters in the right way, they have to be a single value and cannot be used as string replacements (like you're doing). So use this instead
String Query = #"select id from ferien WHERE Datum LIKE #date";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#date", $".{monat}.{jahr}");
command.ExecuteNonQuery();
}
I made a C# form to make a search on two values in one table. My table is called customers with string ID and string cust_name.
I need to make a search query that looks for the textbox Text either is found in ID or in cust_name, so I made this SQL query when textChanged sends this method
search(txt_search.Text);
SqlDataAdapter searchAdapter;
private void search(string id)
{
searchAdapter = new SqlDataAdapter(#"Select * from Customers
where cust_ID like '%' '" + id + "' '%' or
cust_name like '%' '" + id + "' '%'", User.connection);
}
Please help me make it right..
As usual, use a parameterized query. Your error is in the concatenation of the string parts that makes your query. And it is a common situation that something is not as it should be. In your particular case there are some spaces that mess up the syntax. Anyway parameters allow a clearer query text, avoid Sql Injection and parsing errors.
private void search(string id)
{
string cmdText = #"Select *
from Customers
where cust_ID like #id or
cust_name like #id";
searchAdapter = new SqlDataAdapter(cmdText, User.connection);
searchAdapter.SelectCommand.Parameters.Add("#id", SqlDbType.NVarChar).Value = "%" + id + "%";
... remainder of the code that uses the searchAdapter....
}
This Oracle SQL query written in c# is giving me the following error : invalid character
qur = " select * from emp where name LIKE '%" + TextBox1.Text + "%'";
How can I solve this?
The problem is your query is very open to Sql Injection attacks. Since you are not using parametrized queries anything entered in TextBox1 can crush your query.
for example if I enter : ' char in Textbox your query will be select * from emp where name LIKE '%'%' and it will throw error. And apart from that it is vulnerability and you should not use such queries.
You can change query to :
SqlCommand cmd= new SqlCommand( " select * from emp where name LIKE #myParam");
cmd.Parameters.AddWithValue("#myParam", "%" + TextBox1.Text + "%");
you missed #
How do parameterized queries help against SQL injection?
C# constructing parameter query SQL - LIKE %
you should use it as below:
qur = " select * from emp where name LIKE '%'" + TextBox1.Text + "'%'";
i have this sql query
"select * from table where name like ?"
but I want it to work as
"select * from table where name like ?* "
what is the query please
I am using access with c#
Add * to your parameter. I.e., instead of
myCommand.Parameters.AddWithValue("#search", searchValue);
use
myCommand.Parameters.AddWithValue("#search", searchValue + "*");
Keep your SQL as it is.
If you want to do a wildcard search (instead of a "literal *"), note that ADO.NET uses %, not *:
myCommand.Parameters.AddWithValue("#search", searchValue + "%");