在 C# 中使用 Dapper 将数据发送到 RECORD 类型的 PL/SQL 脚本变量会更好吗

Posted

技术标签:

【中文标题】在 C# 中使用 Dapper 将数据发送到 RECORD 类型的 PL/SQL 脚本变量会更好吗【英文标题】:How is it better to send data using Dapper in c# to PL/SQL scripts variables of RECORD type 【发布时间】:2018-04-09 18:03:55 【问题描述】:

我有一个 PL/SQL 过程,它使用 3 个 RECORD 类型的变量作为参数,我必须用我的数据(来自 c# 应用程序)填充这些变量来执行一个过程。

第一次我尝试通过 c# 使用此记录构建相同的结构并通过 Dapper 作为参数传递,但它不起作用,因为 dapper 仅适用于标量数据类型。

然后我尝试将我的数据作为数组传递并将它们映射到过程中,但是 RECORD 类型不能接受像a.NAME := ('aaaaaa','sdasd'); 这样的数据集,它只能这样工作:

a.NAME(1) := 'aaaaaa';
a.NAME(2) := 'sdasd';

我现在唯一想到的就是在过程文本中生成这样的字符串,但我觉得应该有更好的方法。做错了什么?

附:毕竟我不能改变需要运行的脚本,所以我不能改变它接受的数据类型。

更新: 为了方便起见,假设我决定举个例子:

我们有 2 种自定义类型

TYPE A_REC IS RECORD (NAME dbms_sql.Varchar2_Table);
TYPE B_REC IS RECORD (NAME dbms_sql.Varchar2_Table
                         , ID dbms_sql.Number_Table);

和一个过程,可能会使用类似的东西

declare
a c_pck.a_rec;
b c_pck.b_rec;
begin

a.NAME(1) := 'aaaaa';
b.NAME(1) := 'sssss';
b.NAME(2) := 'ddddd';
b.ID(1) := 111;
b.ID(2) := 222;


c_pck.pr(a => a, b => b);
end;

如何通过 Dapper 运行此程序?

【问题讨论】:

【参考方案1】:

我不能 100% 确定这是否适用于 PL\SQL,但是您可以将 SQL 表值参数传递到您从 Dapper 调用的存储过程中。 RECORD 类型听起来很像,所以它可以工作。

您需要使用DataTable 来构造您的RECORD。您定义的列的顺序必须与它们在数据库中出现的顺序相同。

来自以下链接:

var dt = new DataTable();
dt.Columns.Add("AUDIT_PK", typeof (long));
dt.Columns.Add("MESSAGE", typeof (string));
dt.Columns.Add("SUCCESS", typeof (bool));
dt.Rows.Add(1, "EHLO", null);

using (var conn = new SqlConnection("Data Source=.;Initial  Catalog=Scratch;Integrated Security=true"))

    conn.Open();
    conn.Execute("TestOne", new TVP =   dt.AsTableValuedParameter("dbo.AUDITRECORD"), commandType: CommandType.StoredProcedure);

https://www.codeproject.com/Articles/835519/Passing-Table-Valued-Parameters-with-Dapper

【讨论】:

以这种方式在Oracle.ManagedDataAccess.Client.OracleParameter.set_Value(Object value) 中获取System.ArgumentException: value out of rangeDapper.TableValuedParameter.Set(IDbDataParameter parameter, DataTable table, String typeName) 等中【参考方案2】:

你需要在这里处理两个不同的事情。

    告知 Oracle 驱动程序您的自定义数据类型

在这里,您将需要相当多的样板文件。 您必须使用IOracleCustomType 接口为您的UDT 编写映射代码。 Here's官方文档。 This guide 似乎是一个很好的资源。

    向 Dapper 介绍您的自定义数据类型

Dapper 有一个硬编码的 .NET 类型列表,映射到 DbTypes。 您可以添加到此列表,但只能添加到通用 DbTypes。 要使用特定于数据库的功能,您的参数必须实现 SqlMapper.ICustomQueryParameter(这就是表值 SQL server 工作的东西)。在您的AddParameter 实现中,您可以手动构造一个OracleParameter 并正确设置UDT 类型名。 返回值应该由 Dapper 处理得很好,因为这只是映射像

这样的结果集

【讨论】:

听起来很有趣,但我使用的是 Oracle,而不是 PG 会寻找这样的东西 那是我将 PL/SQL 完全误读为 PLPGSQL。对此感到抱歉:-) 无论如何,控制如何创建参数的简洁界面将是相同的。那么我认为你必须查看OracleCustomTypeMapping 属性来指导Oracle 关于你的数据。 想在我可以访问的 oracle 开发基础上做一些快速测试,但不幸的是,“ODP.NET,托管驱动程序不支持 UDT 和 .NET 自定义类型”。我没有用不受管理的东西污染我的视觉工作室,对不起:)

以上是关于在 C# 中使用 Dapper 将数据发送到 RECORD 类型的 PL/SQL 脚本变量会更好吗的主要内容,如果未能解决你的问题,请参考以下文章

C# Dapper基本三层架构使用 (Model)

使用C#的DAPPER 进行增删改查操作(准备工作)

将 Dapper 与 SQL Server 一起使用

使用 Dapper (C#) 调用 PostgreSQL 存储过程

选择语句:列名无效,在 C# 中使用 Dapper

在 C# 中使用 Dapper 读取表的子集