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

如何使用Dapper与Oracle将数对集合传入IN子句作为参数?

使用Dapper和Oracle参数化多列IN查询的两种方法

针对需要将(COLUMN_A, COLUMN_B)数对集合作为参数传入Oracle查询的场景,以下是两种可行的实现方式:

方法一:使用Oracle自定义对象与嵌套表(推荐大量数对场景)

Oracle支持通过自定义UDT(用户定义类型)传递集合参数,步骤如下:

1. 在Oracle数据库创建自定义类型

先在数据库中定义存储数对的对象类型,以及包含该对象的嵌套表类型:

CREATE TYPE PAIR_TYPE AS OBJECT (
    A NUMBER,
    B NUMBER
);
/

CREATE TYPE PAIR_TABLE_TYPE AS TABLE OF PAIR_TYPE;
/

2. C#中定义对应实体类

public class Pair
{
    public int A { get; set; }
    public int B { get; set; }
}

3. 转换C#集合为Oracle UDT参数并执行查询

需要将C#的List<Pair>转换为Oracle识别的嵌套表参数,再通过Dapper执行查询:

var targetPairs = new List<Pair>
{
    new Pair { A = 1, B = 2 },
    new Pair { A = 3, B = 4 },
    new Pair { A = 5, B = 6 }
};

// 构造Oracle自定义类型参数
var pairTableParam = new OracleParameter("parameters", OracleDbType.Object, ParameterDirection.Input);
pairTableParam.UdtTypeName = "PAIR_TABLE_TYPE";
pairTableParam.Value = ConvertToOraclePairTable(targetPairs, connection);

// 执行Dapper查询
var result = connection.Query<string>(@"
    SELECT COLUMN_C FROM SOME_TABLE
    WHERE (COLUMN_A, COLUMN_B) IN (SELECT A, B FROM TABLE(:parameters))
", new { parameters = pairTableParam });

补充:C#集合转Oracle UDT的工具方法

private static OracleUdt ConvertToOraclePairTable(List<Pair> pairs, OracleConnection connection)
{
    // 创建嵌套表UDT实例
    var tableUdt = OracleUdt.CreateUdt(connection, "PAIR_TABLE_TYPE");
    var array = (OracleArrayType)tableUdt.Value;

    // 逐个将C# Pair转换为对象UDT
    for (int i = 0; i < pairs.Count; i++)
    {
        var pairUdt = OracleUdt.CreateUdt(connection, "PAIR_TYPE");
        pairUdt.SetValue("A", pairs[i].A);
        pairUdt.SetValue("B", pairs[i].B);
        array.SetValue(i, pairUdt);
    }

    tableUdt.Value = array;
    return tableUdt;
}

方法二:动态生成参数占位符(适合少量数对场景)

如果不需要创建数据库类型,可以通过动态生成参数名和IN子句的方式实现,代码更简洁:

var targetPairs = new List<Pair>
{
    new Pair { A = 1, B = 2 },
    new Pair { A = 3, B = 4 },
    new Pair { A = 5, B = 6 }
};

var parameters = new DynamicParameters();
var inClauseSegments = new List<string>();

// 为每个数对生成独立参数
for (int i = 0; i < targetPairs.Count; i++)
{
    var aParam = $"pair_{i}_a";
    var bParam = $"pair_{i}_b";
    inClauseSegments.Add($"(:{aParam}, :{bParam})");
    parameters.Add(aParam, targetPairs[i].A, OracleDbType.Int32);
    parameters.Add(bParam, targetPairs[i].B, OracleDbType.Int32);
}

// 拼接完整SQL并执行
var sql = $"SELECT COLUMN_C FROM SOME_TABLE WHERE (COLUMN_A, COLUMN_B) IN ({string.Join(", ", inClauseSegments)})";
var result = connection.Query<string>(sql, parameters);

两种方法对比

  • 自定义类型法:无参数数量限制,符合Oracle最佳实践,但需要提前在数据库创建类型,代码相对复杂。
  • 动态参数法:无需数据库变更,代码简洁,但数对数量过多时(如超过数百个)可能触发Oracle的参数数量或SQL长度限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:24:07