Npgsql.PostgresException:'42601:“ $ 1”或附近的语法错误'

时间:2018-12-14 11:01:25

标签: c# postgresql dapper

具有以下查询:

select count(t.*)
from template t
where t.available = true
    and exists (select *
                from tag
                join template_tag on template_tag.tag_id = tag.id
                where template_tag.template_id = t.id and tag.name in @tags)

并将dapper动态参数设置为:

new { Tags = new List<string> { "tagExample" } }

运行查询时出现以下错误:

  

Npgsql.PostgresException:'42601:“ $ 1”或附近的语法错误'

我已经检查了PostgreSQL, Npgsql returning 42601: syntax error at or near "$1",但没有帮助,所以这一定是另一个问题。

最小示例:

const string query = @"
    select count(t.*)
    from template t
    where exists (select *
                  from template_module tm
                  where tm.template_id = t.id and tm.module_properties in @props)
";

var parameters = new { props = new List<string> { "{}"} };

var result = await conn.ExecuteScalarAsync<int>(query, parameters);

1 个答案:

答案 0 :(得分:0)

例如;

Tags = new List<string> { "tag1","tag2","tag3" }

也许您可以那样使用

string _tags = "('"+string.Join(",',",Tags)+"')";

string query = "select count(t.*)
    from template t
    where t.available = true
        and exists (select *
                    from tag
                    join template_tag on template_tag.tag_id = tag.id
                    where template_tag.template_id = t.id and tag.name in {_tags})";

所以查询就是这样

select count(t.*)
    from template t
    where t.available = true
        and exists (select *
                    from tag
                    join template_tag on template_tag.tag_id = tag.id
                    where template_tag.template_id = t.id and tag.name in ('tag1','tag2','tag3'))

然后执行

更新:基本上相同的推理

这样的sql注入问题的解决方案

public static class SqlCommandExt
{

    /// <summary>
    /// This will add an array of parameters to a SqlCommand. This is used for an IN statement.
    /// Use the returned value for the IN part of your SQL call. (i.e. SELECT * FROM table WHERE field IN ({paramNameRoot}))
    /// </summary>
    /// <param name="cmd">The SqlCommand object to add parameters to.</param>
    /// <param name="paramNameRoot">What the parameter should be named followed by a unique value for each value. This value surrounded by {} in the CommandText will be replaced.</param>
    /// <param name="values">The array of strings that need to be added as parameters.</param>
    /// <param name="dbType">One of the System.Data.SqlDbType values. If null, determines type based on T.</param>
    /// <param name="size">The maximum size, in bytes, of the data within the column. The default value is inferred from the parameter value.</param>
    public static SqlParameter[] AddArrayParameters<T>(this SqlCommand cmd, string paramNameRoot, IEnumerable<T> values, SqlDbType? dbType = null, int? size = null)
    {
        /* An array cannot be simply added as a parameter to a SqlCommand so we need to loop through things and add it manually. 
         * Each item in the array will end up being it's own SqlParameter so the return value for this must be used as part of the
         * IN statement in the CommandText.
         */
        var parameters = new List<SqlParameter>();
        var parameterNames = new List<string>();
        var paramNbr = 1;
        foreach (var value in values)
        {
            var paramName = string.Format("@{0}{1}", paramNameRoot, paramNbr++);
            parameterNames.Add(paramName);
            SqlParameter p = new SqlParameter(paramName, value);
            if (dbType.HasValue)
                p.SqlDbType = dbType.Value;
            if (size.HasValue)
                p.Size = size.Value;
            cmd.Parameters.Add(p);
            parameters.Add(p);
        }

        cmd.CommandText = cmd.CommandText.Replace("{" + paramNameRoot + "}", string.Join(",", parameterNames));

        return parameters.ToArray();
    }

}

并使用它。.

var cmd = new SqlCommand("select count(t.*)
        from template t
        where t.available = true
            and exists (select *
                        from tag
                        join template_tag on template_tag.tag_id = tag.id
                        where template_tag.template_id = t.id and tag.name in ({Tags}))");
cmd.AddArrayParameters("Tags", Tags);