You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Dapper TypeHandler<string[]>时IN条件SQL语法错误求助

Dapper连接MySQL时,自定义StringArrayHandler导致IN查询语法错误

问题背景

使用Dapper连接MySQL,自定义StringArrayHandler用于将数据库字符串解析为string[](因TypeHandler要求必须同时重写Parse和SetValue方法)。但执行包含IN(...)条件的查询时触发SQL语法错误,仅将参数数组转为List<string>可正常运行,但该方式易因遗忘转换引发问题。

示例代码

业务查询代码

using (var db = ADA_BaseDBManager.CreateADA_BaseDBConnectionDapper())
{
    SqlMapper.AddTypeHandler(new StringArrayHandler());

    var superOdps = new string[]{"0200258416_70","0200258438_20","0200258649_10","0100942638_30","0200258768_10"};

    var sql = "select * from odps_v2 ov where ov.ID_SuperODP in @superOdps";

    var data = db.Query<DTOODP>(sql, new { superOdps});

    return data;
}

自定义TypeHandler代码

public class StringArrayHandler : SqlMapper.TypeHandler<string[]>
{
    public override string[] Parse(object value)
    {
        if (value == null || value == DBNull.Value)
        {
            return null;
        }

        return Utils.SerializedToArray(value.ToString());
    }

    public override void SetValue(IDbDataParameter parameter, string[] value)
    {
        parameter.Value = $"('{Utils.ArrayToSerialized(value, "','")}')";
    }
}

异常信息

{"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''(\'0200258416_70\',\'0200258438_20\',\'0200258649_10\',\'0100942638_30\',\'0200' at line 1"}

问题原因

全局注册的StringArrayHandler会将传入的string[]参数转换为带括号的字符串,Dapper会把这个字符串作为单个参数包裹在引号中,最终生成的SQL为:

select * from odps_v2 ov where ov.ID_SuperODP in '(\'0200258416_70\',\'0200258438_20\',...)'

这不符合SQL语法规范,IN后应紧跟括号包裹的多个值,而非带引号的单个字符串。

而转为List<string>能正常运行,是因为Dapper对IEnumerable类型参数有原生处理逻辑,会自动拆分为多个独立参数,不会被自定义TypeHandler干扰。

解决方案

方案1:仅在DTO属性上指定TypeHandler(推荐)

如果StringArrayHandler仅用于读取数据库字段并转换为DTO的string[]属性,无需全局注册,只需在DTO的对应属性上标记即可:

public class DTOODP
{
    // 其他属性...
    [TypeHandler(typeof(StringArrayHandler))]
    public string[] TargetArrayProperty { get; set; }
}

修改业务代码,移除全局注册的TypeHandler,直接传入string[]参数:

using (var db = ADA_BaseDBManager.CreateADA_BaseDBConnectionDapper())
{
    var superOdps = new string[]{"0200258416_70","0200258438_20","0200258649_10","0100942638_30","0200258768_10"};

    var sql = "select * from odps_v2 ov where ov.ID_SuperODP in @superOdps";

    var data = db.Query<DTOODP>(sql, new { superOdps});

    return data;
}

此时Dapper会自动将string[]拆分为多个参数,生成正确的SQL:

select * from odps_v2 ov where ov.ID_SuperODP in (@superOdps0, @superOdps1, @superOdps2, @superOdps3, @superOdps4)

既避免语法错误,又能防止SQL注入。

方案2:避免用TypeHandler处理IN查询参数

自定义TypeHandler的设计目标是处理单个参数与数据库字段的双向转换,不适合处理IN查询所需的多参数场景。因此,不要用TypeHandler来处理作为IN条件的数组参数,直接依赖Dapper的原生IEnumerable参数支持即可。


内容的提问来源于stack exchange,提问作者Brakes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:22:48