在PostgreSQL上使用ExecuteSqlRawAsync的C# 11原始字符串文字有区分大小写的问题

63lcw9qa  于 12个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(150)

我在尝试修改SQL查询以解决有关潜在SQL注入的警告时遇到了一个问题。我打算对查询进行参数化并使用原始字符串文字,但我收到了一条错误消息。
这个错误似乎与我的列名的大小写敏感性有关,不幸的是,我不能改变整个数据库来删除它们。
我已经尝试了各种其他方法,但它们要么导致错误,要么无法正确检索UserId。
下面是我试过的代码。
1.原始版本(SQL注入问题)

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 $$"
);

字符串
1.原始字符串文字版本
(错误:Npgsql.PostgresException:42703:列“userid”不存在)

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);


1.带有ExecuteSqlInterpolatedAsync的原始字符串文本版本
(错误:Npgsql.PostgresException:42703:列“p0”不存在)

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 $$
""");


我希望你能告诉我如何进行修改。
感谢您的帮助!

iaqfqrcu

iaqfqrcu1#

IF实际上不是必需的,所以你可以使用一个普通的SqlInterpolated块(即完全参数化)。

await dbContext.Database.ExecuteSqlInterpolatedAsync(
$"""
    DELETE FROM "Notification"
    WHERE "UserId" = {userId}
      AND "IsReceived" = TRUE
      AND "ContentId" NOT IN (
          SELECT n2."ContentId"
          FROM "Notification" n2
          WHERE n2."UserId" = {userId}
          ORDER BY n2."CreatedAt" DESC
          LIMIT 20
      );
""");

字符串

s8vozzvw

s8vozzvw2#

AFAIK你不能使用DO的参数。从docs
DO执行匿名代码块,或者换句话说,在过程语言中执行临时匿名函数。
代码块被视为没有参数的函数体,返回void。它被解析并执行一次。
因此它将参数名视为列名(显然失败了)。
因此,只需重写查询,这样就不需要DO,或者创建一个数据库函数并使用EF调用它。
参见this answer

相关问题