I encountered an issue while attempting to modify my SQL query to address warnings about potential SQL injection. I aimed to parameterize the query and use raw string literals, but I received an error message instead.
It seems the error is related to the case sensitivity of my column names, and unfortunately, I can't alter the entire database to lowercase them.
I've experimented with various other approaches, but they either resulted in errors or failed to correctly retrieve the UserId.
Below is the code I tried.
- Original Version (SQL injection problem)
await dbContext.Database.ExecuteSqlRawAsync(
$@"
DO $$
BEGIN
IF (SELECT COUNT(*) FROM ""Notification"" WHERE ""UserId"" = '{userId}') > 20 THEN
DELETE FROM ""Notification""
WHERE ""UserId"" = '{userId}' AND ""IsReceived"" = 'TRUE' AND ""ContentId"" NOT IN (
SELECT ""ContentId"" FROM ""Notification""
WHERE ""UserId"" = '{userId}'
ORDER BY ""CreatedAt"" DESC
LIMIT 20
);
END IF;
END $$"
);
- Raw string literals Version
(error: Npgsql.PostgresException : 42703: column "userid" does not exist)
var param = new NpgsqlParameter("@UserId", userId);
await dbContext.Database.ExecuteSqlRawAsync(
"""
DO $$
BEGIN
IF (SELECT COUNT(*) FROM "Notification" WHERE "UserId" = @UserId) > 20 THEN
DELETE FROM "Notification"
WHERE "UserId" = @UserId AND "IsReceived" = 'TRUE' AND "ContentId" NOT IN (
SELECT "ContentId" FROM "Notification"
WHERE "UserId" = @UserId
ORDER BY "CreatedAt" DESC
LIMIT 20
);
END IF;
END $$
""", param);
- Raw string literals Version with ExecuteSqlInterpolatedAsync
(error: Npgsql.PostgresException : 42703: column "p0" does not exist)
await dbContext.Database.ExecuteSqlInterpolatedAsync(
$"""
DO $$
BEGIN
IF (SELECT COUNT(*) FROM "Notification" WHERE "UserId" = {userId}) > 20 THEN
DELETE FROM "Notification"
WHERE "UserId" = {userId} AND "IsReceived" = 'TRUE' AND "ContentId" NOT IN (
SELECT "ContentId" FROM "Notification"
WHERE "UserId" = {userId}
ORDER BY "CreatedAt" DESC
LIMIT 20
);
END IF;
END $$
""");
I'd appreciate guidance on the best way to proceed with modifications.
Thank you for your assistance!
{userId}parameters. Triple quoting does not alter the case of the string, so there's something else happening in your #2 snippet.FormattableStringaccepted byExecuteSqlInterpolatedAsync. Otherwise it would have all the same SQL injections problems as the first one and there would be no point in introduction of such method.RelationalDatabaseFacadeExtensions.ExecuteSqlInterpolatedAsync- "Any parameter values you supply will automatically be converted to a DbParameter."FormattableString, not juststring. Compiler will not build thestringand this allows EF to see all the{}placeholders and their values and turn them into query parameters.