Frage

I would like to make parameterized query for SQLquery that can be something like this:

SELECT * FROM Table1 WHERE Col1 IN (SELECT Col2 FROM Table2 WHERE Col3 IN (1, 2, 3));

The values come from WS interface and although I can trust the consumers I want to play it safe and use parameterized query involving DbParameters to prevent SQL injection. How to do it?

Thanks!

War es hilfreich?

Lösung

The key point, as you note, is to use parameters. IN clauses are notoriously problematic for that, annoyingly. Now, if you know the values are all integers (for example you are taking an int[] parameter to your C# method), then you can just about get away with things like:

cmd.CommandText = "SELECT * FROM Table1 WHERE Col1 IN (SELECT Col2 FROM Table2 WHERE Col3 IN ("
+ string.Join(",", values) + "))"; // please don't!!!

It is horrible, suggests a very bad practice (if somebody copies it for strings, you are in a world of pain), and can't use query plan caching. You could do something like:

var sb = new StringBuilder("SELECT * FROM Table1 WHERE Col1 IN (SELECT Col2 FROM Table2 WHERE Col3 IN (");
int idx = 0;
foreach(var val in values) {
    if(idx != 0) sb.Append(',');
    sb.Append("@p").Append(idx);
    cmd.Parameters.AddWithValue("@p" + idx, val);
    idx++
}
sb.Append("))");
cmd.CommandText = sb.ToString();

Which is preferable but awkward.

Or simplest: with a tool like dapper, let the library worry about it:

var data = conn.Query<YourType>(
    "SELECT * FROM Table1 WHERE Col1 IN (SELECT Col2 FROM Table2 WHERE Col3 IN @values)",
    new { values });

Here dapper spots the usage and "does the right thing". It also handles the "0 values" case for you.

Andere Tipps

Here is one example:

SqlCommand cmd = new SqlCommand("SELECT * FROM Table1 WHERE Col1 IN (SELECT Col2 FROM Table2 WHERE Col3 = @myparam", conn);

//define parameters used in command object
SqlParameter param  = new SqlParameter();
param.ParameterName = "@myparam";
param.Value         = "myvalue";

//add new parameter to command object
cmd.Parameters.Add(param);

// get data stream
reader = cmd.ExecuteReader();

Check out this link for more details: http://csharp-station.com/Tutorial/AdoDotNet/Lesson06

The difficulty here is parameterizing each individual IN clause so that you can pass through a variable number of IDs.

Have a look at this useful article as to one approach to solve this: http://www.mikesdotnetting.com/Article/116/Parameterized-IN-clauses-with-ADO.NET-and-LINQ

Basically, it involves a little bit of string manipulation to build up the parameterized list of IN clauses, so you end up with a SQL statement that looks like this for your particular example with 3 IDs:

select * from TABLE1 where COL1 in (select COL2 from TABLE2 where COL3 IN (@p1, @p2, @p3));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top