4

I'm trying construct a MySQL query in my C# application, I'm wondering if it's possible to use OR statement in a MySQL parameters.

I have a list of names, and I want to check and see what are the names that exist in the database already. Here's a short example

List<string> names = new List<string> {"adam", "bob", "cathy"}; //actual list is much longer
MySqlConnection connection = getAndOpenConnection();
MySqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Employees WHERE name = @names";
command.Parameters.Add(new MySqlParameters("@names", String.Format("names = {0}", String.Join(names, " or name = ")))); //is this line legal?

My original idea is to construct the command text this way:

command.CommandText = String.Format("SELECT * FROM Employees WHERE name = '{0}'", String.Join(names, "' or name = '"))

The code will give me the correct command text I want, but I really want to prevent SQL injection.

Can someone please help me out on how to construct the MySqlCommand properly?

sora0419
  • 2,308
  • 9
  • 39
  • 58
  • 4
    `String.Join(names, " or name = ")` this line is string concatenation and would be prone to SQL Injection. You need a WHERE IN clause, See this http://stackoverflow.com/questions/337704/parameterize-a-sql-in-clause, instead of Accepted Answer , see [this](http://stackoverflow.com/a/337792/961113) answer – Habib Jun 27 '14 at 16:01
  • @Habib thank you, this seems like it will solve my problem, I'll definitely give it a try! – sora0419 Jun 27 '14 at 16:15

1 Answers1

3

Not easily, no. You need to make that an IN query, which is a pain to do with parameterization (which you really should do). Basically, you have two options:

  • build the appropriate command and parameters based on the array size
  • use a tool that will do it for you

The latter is easier; with "dapper", this is just:

connection.Query("SELECT * FROM Employees WHERE name in @names", new { names })
          .ToList();

(which will be a List<dynamic>; if you have an Employee class that matches the columns, you can use connection.Query<Employee>(...).ToList() to get a List<Employee> instead).

The former, though, is more like (for a simple version):

var sb = new StringBuilder("SELECT * FROM Employees WHERE name=@name0");
cmd.Parameters.AddWithValue("name0", names[0]);
for(int i = 1; i < names.Count ; i++) {
    sb.Append(" or name=@name").Append(i);
    cmd.Parameters.AddWithValue("name" + i, names[i]);
}
cmd.CommandText = sb.ToString();

There are a few other ways of doing that too:

switch(names.Count)
{
    case 0: cmd.CommandText = "SELECT * FROM Employees"; break;
    case 1:
        cmd.CommandText = "SELECT * FROM Employees WHERE name=@name";
        cmd.Parameters.AddWithValue("name", names[0]);
        break;
    default:
        var sb = new StringBuilder(
            "SELECT * FROM Employees WHERE name IN (@name0")
        cmd.Parameters.AddWithValue("name0", names[0]);
        for(int i = 1;i<names.Count;i++) {
            sb.Append(",@name").Append(i);
            cmd.Parameters.AddWithValue("name" + i, names[i]);
        }
        cmd.CommandText = sb.Append(")").ToString();
        break;
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900