I am trying to convert my sql queries being run with EF Core’s .FromSqlRaw() method into queries to be run with .FromSqlInterpolated() so they are less vulnerable to SQL injection attacks. I’ve gotten almost everything converted and working fine, but the one thing that is stumping me is how to filter by a list of integers in an or configuration on a single field.
The database is postgres, and the quotes are because I used code first EF Core which means that all of the tables are capitalized like the class. ProjectTypeId is an integer column in my table, and projectTypes is a List<int>
type variable.
The code in my where clause I’m trying to replace is:
WHERE ""PartGroups"".""ProjectTypeId"" IN({string.Join(",", projectTypes)})
The closest I’ve been able to get to getting it working is with this:
""PartGroups"".""ProjectTypeId""::text IN({string.Join(",", projectType)})
or
""PartGroups"".""ProjectTypeId""::text LIKE ANY(ARRAY[{string.Join(",", projectTypes)}])
These will work when there is only one value in projectTypes, but any more than that and it fails. I don’t know how to view the resulting query + parameter set, just the query, so I’m not sure what’s it’s doing to the parameter, so I’ve been struggling to figure out something that works. Also, the query has ~80 parameters total, so manually setting each one with a raw query isn’t really feasible.
3
Answers
So I found a way to actually see how EF Core is interpreting the parameters for the interpolated query and was able to play around with it to get what I wanted out of it. So just in case someone wants to or needs to stick to a pure interpolated query, you can use the following pattern for your needs:
This also works with text values (just no need to cast to text) and you can use wildcards like this:
One way you could approach it, perhaps, is to leverage EF’s ability to compose over the top of a raw
EF will put your SQL in as a sub query and write the IN for you in the outer. The DB query optimizer will (probably) then push the IN into the sub query if it can..
If you want to have a look at the SQL EF made and you’re on EF5+ the easiest thing to do is do everything apart from ToList/ToArray, and capture the queryable:
Then pause in the debugger and look at the DebugView property of the
q
. You’ll get the full SQL text and you can slot it into SSMS and inspect the execution plan, check it runs the same as a single level (non hierarchical) query..The other thing you can do, is create your query in a FormattableString yourself. So long as FromSqlInterpolated receives a FormattableString it will pull it apart and parameterize
It’s, of course, possible to write a helper to do this for you…