注册

如何通过 ado.net 向存储过程传自定义类型参数

忆殇 2025/12/02 234 4

环境:

【DM版本】: DM Database Server 64 V8
【操作系统】:麒麟 V10
【CPU】: Kunpeng-920
【驱动】: NuGet Gallery | DM.DmProvider 8.3.1.37876
【问题描述】*:如何通过 ado.net 向存储过程传自定义类型参数?

我已经看到社区内的相关问答 存储过程中传参为自定义类型,如何解决? | 达梦技术社区,但是并没有获得有用信息。

我的测试用例如下

C# 类

public class GeneralType { public int Id { get; set; } public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } public string Value4 { get; set; } public string Value5 { get; set; } }

UDT

-- 定义复合类型 - row CREATE OR REPLACE TYPE GeneralTableRow AS OBJECT ( "Id" INT, "Value1" VARCHAR(32767), -- VARCHAR(32767) 是C# string类型自动映射到达梦数据库的默认类型 "Value2" VARCHAR(32767), "Value3" VARCHAR(32767), "Value4" VARCHAR(32767), "Value5" VARCHAR(32767) ); -- 定义复合类型 - table CREATE OR REPLACE TYPE GeneralTableType AS TABLE OF GeneralTableRow;

数据表

CREATE TABLE "TestEntities"( "Id" INT IDENTITY(1, 1), "Code" VARCHAR2(100), "Name" VARCHAR2(300), "DateTimeValue" TIMESTAMP(6) NOT NULL, "DecimalValue" DECIMAL(12,2) NOT NULL, "BooleanValue" BIT DEFAULT 0 NOT NULL, CONSTRAINT "PK_TestEntities" NOT CLUSTER PRIMARY KEY("Id") ) STORAGE(ON "MAIN", CLUSTERBTR);

存储过程

CREATE OR REPLACE PROCEDURE UpdateTestEntities( data IN GeneralTableType -- 批量更新数据(自定义表类型) ) AS BEGIN -- 遍历批量数据,逐行更新(FORALL批量更新,效率更高,且为事务操作) FORALL i IN 1..data.COUNT UPDATE "TestEntities" SET "Code" = data(i).Value1, "Name" = data(i).Value2, "DateTimeValue" = TO_TIMESTAMP(data(i).Value3, 'YYYY-MM-DD HH24:MI:SS.FF6'), -- 转换为TIMESTAMP "DecimalValue" = TO_NUMBER(data(i).Value4, '9999999999.99'), -- 转换为DECIMAL "BooleanValue" = CAST(data(i).Value5 AS BIT) WHERE "Id" = data(i).Id; END;

验证存储过程

✅ 代码能正常执行,且表中数据被修改,符合预期。

DECLARE -- data_list 是我们本地的变量名 data_list GENERALTABLETYPE; -- 声明一个变量来存储受影响的行数(可选,存储过程本身不返回,但 FORALL 会影响 SQL%ROWCOUNT) v_rows_affected INT; BEGIN -- 初始化集合变量 data_list := GENERALTABLETYPE(); -- 向集合中添加数据行 -- 确保 Id 存在于您的 TestEntities 表中 data_list.EXTEND(2); -- 扩展集合以容纳 2 行数据 -- 插入第一行数据 data_list(1) := GENERALTABLEROW( 4, -- Id 'CODE_A_DB', -- Value1 (Code) 'Name A Updated DB Call', -- Value2 (Name) '2025-12-01 10:00:00.000', -- Value3 (DateTimeValue - 字符串格式) '150.75', -- Value4 (DecimalValue - 字符串格式) '1' -- Value5 (BooleanValue - 字符串 '1' 或 '0') ); -- 插入第二行数据 data_list(2) := GENERALTABLEROW( 5, -- Id 'CODE_B_DB', -- Value1 'Name B Updated DB Call', -- Value2 '2025-12-01 11:00:00.000', -- Value3 '200.00', -- Value4 '0' -- Value5 ); -- 调用存储过程,并将准备好的集合作为参数传入 UpdateTestEntities(data_list); -- 可选:打印或查看受影响的总行数 -- 在达梦 PL/SQL 中,FORALL 后的 SQL%ROWCOUNT 表示总数 v_rows_affected := SQL%ROWCOUNT; DBMS_OUTPUT.PUT_LINE('Total affected rows: ' || v_rows_affected); -- 提交事务 COMMIT; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM); ROLLBACK; END;

ado.net 调用

// [TestMethod] public async Task StoredProcedureWithComplexTypeParameterTest() { var data = new List<GeneralType> { new GeneralType { Id = 4, Value1 = "CODE004", Value2 = "Test Entity updated by ado.net", Value3 = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), Value4 = "100.00", Value5 = true.ToString() }, new GeneralType { Id = 5, Value1 = "CODE005", Value2 = "Test Entity updated by ado.net", Value3 = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), Value4 = "200.00", Value5 = false.ToString() } }; var conn = new DmConnection(Configuration.GetConnectionString("Dm")); var command = new DmCommand("UpdateTestEntities", conn) { CommandType = System.Data.CommandType.StoredProcedure, }; var parameter = new DmParameter() { ParameterName = "data", DbType = System.Data.DbType.Object, DmSqlTypeName = "GENERALTABLETYPE", Value = data }; command.Parameters.Add(parameter); await command.ExecuteNonQueryAsync(); }

进行的几个传参尝试及结果

❌ List<GeneralType>: parameter.Value = data;

消息:  Test method DmAdoTests.StoredProcedureTests.StoredProcedureWithComplexTypeParameterTest threw exception: System.SystemException: Value is of unknown data type 堆栈跟踪:  DmCommand.BindParameters(Int32& rowCount, DmDataReader rd, CommandBehavior behavior) DmCommand.do_ExecuteNonQuery() DmCommand.ExecuteNonQuery() DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)

❌ Array<GeneralType>: parameter.Value = data.ToArray();

消息:  Test method DmAdoTests.StoredProcedureTests.StoredProcedureWithComplexTypeParameterTest threw exception: System.Exception: 非Array类型入参无法使用Array进行绑定 堆栈跟踪:  DmCommand.BindParameters(Int32& rowCount, DmDataReader rd, CommandBehavior behavior) DmCommand.do_ExecuteNonQuery() DmCommand.ExecuteNonQuery() DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)

❌ json-string: parameter.Value = System.Text.Json.JsonSerializer.Serialize(data);

消息:  Test method DmAdoTests.StoredProcedureTests.StoredProcedureWithComplexTypeParameterTest threw exception: System.InvalidCastException: Specified cast is not valid. 堆栈跟踪:  DmCommand.BindParameters(Int32& rowCount, DmDataReader rd, CommandBehavior behavior) DmCommand.do_ExecuteNonQuery() DmCommand.ExecuteNonQuery() DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)

❌ 转换为DataTable: parameter.Value = MetadataHelper.ToDataTable(data);

消息:  Test method DmAdoTests.StoredProcedureTests.StoredProcedureWithComplexTypeParameterTest threw exception: System.SystemException: Value is of unknown data type 堆栈跟踪:  DmCommand.BindParameters(Int32& rowCount, DmDataReader rd, CommandBehavior behavior) DmCommand.do_ExecuteNonQuery() DmCommand.ExecuteNonQuery() DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)

如果您有解决方案或者任何看法,请不吝赐教,期待在评论区看到您的留言 🌹🌹🌹

回答 0
暂无回答
扫一扫
联系客服