ASP.NET Core 中使用 Dapper 的 Oracle 存储过程输出参数

介绍

Oracle 数据库功能强大,在企业环境中使用广泛。在 ASP.NET Core 应用程序中使用 Oracle 存储过程时,处理输出参数可能具有挑战性。本教程将指导您完成使用 Dapper(适用于 . NET 的轻量级 ORM(对象关系映射器))解锁 Oracle 存储过程输出参数的过程。

先决条件

在开始之前,请确保您已准备好以下内容。

  • Visual Studio 2019 或更高版本
  • .NET Core SDK 3.1 或更高版本
  • Oracle 数据库(您可以使用 Oracle 数据库 XE 进行开发)
  • 具有 C#、ASP.NET Core 和 SQL 的基础知识

设置项目

创建 ASP.NET 核心项目

打开 Visual Studio 并创建一个新的 ASP.NET Core 控制台应用程序项目。

安装 NuGet 包

您需要安装 Dapper 和 Oracle.ManagedDataAccess.Core 包。

创建 Oracle 存储过程

让我们在 Oracle 中创建一个简单的存储过程,它接受一个输入参数并返回一个输出参数。

复制代码
CREATE OR REPLACE PROCEDURE DEMO.SAVE_EMPLOYEE_DETAILS (
   V_NAME        IN     VARCHAR2,
   V_ADDRESS     IN     VARCHAR2,
   V_DEPARTMENT  IN     VARCHAR2,
   V_POSITION    IN     VARCHAR2,
   O_EMP_ID      OUT    VARCHAR2,
   O_ERROR       OUT    VARCHAR2
)
AS
   V_EMP_ID VARCHAR2 (10);
BEGIN
   -- GENERATE EMPLOYEE ID
   SELECT DEMO.EMP_SEQ.NEXTVAL INTO V_EMP_ID FROM DUAL;

   -- INSERT EMPLOYEE DETAILS
   INSERT INTO DEMO.EMPLOYEE_DETAILS (
      EMP_ID,
      NAME,
      ADDRESS,
      DEPARTMENT,
      POSITION
   ) VALUES (
      V_EMP_ID,
      V_NAME,
      V_ADDRESS,
      V_DEPARTMENT,
      V_POSITION
   );
   -- SET OUTPUT EMPLOYEE ID
   O_EMP_ID := V_EMP_ID;

   -- RESET ERROR OUTPUT
   O_ERROR := NULL;
EXCEPTION
   WHEN OTHERS THEN
      O_ERROR := 'FAILED TO SAVE EMPLOYEE DETAILS. ' || SQLERRM;
      ROLLBACK;
      RETURN;
END SAVE_EMPLOYEE_DETAILS;
/

连接到 Oracle 数据库

使用 SQL*Plus、SQL Developer、Toad 或任何其他 Oracle 客户端工具连接到您的 Oracle 数据库。

实现 ASP.NET 核心应用程序

添加 OracleDynamicParameters 类

复制代码
using Dapper;
using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace DapperOracleDemo
{
    public class OracleDynamicParameters : SqlMapper.IDynamicParameters
    {
        private readonly DynamicParameters dynamicParameters = new DynamicParameters();
        // 使用DynamicParameters存储一般参数
        private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
        // 使用List<OracleParameter>存储Oracle特定的参数

        public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction, object value = null, int? size = null)
        {
            // 创建并添加一个OracleParameter对象到参数列表中
            OracleParameter item = ((!size.HasValue) ? 
                new OracleParameter(name, oracleDbType, value, direction) : 
                new OracleParameter(name, oracleDbType, size.Value, value, direction));
            oracleParameters.Add(item);
        }

        public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
        {
            // 创建并添加一个没有默认值的OracleParameter对象到参数列表中
            OracleParameter item = new OracleParameter(name, oracleDbType, direction);
            oracleParameters.Add(item);
        }

        public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
        {
            // 将一般参数添加到命令对象中
            ((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
            // 将Oracle特定的参数添加到命令对象中
            (command as OracleCommand)?.Parameters.AddRange(oracleParameters.ToArray());
        }

        public T Get<T>(string name)
        {
            // 获取指定名称的参数值
            var parameter = oracleParameters.SingleOrDefault(t => t.ParameterName == name);
            object val = parameter?.Value;
            if (val == DBNull.Value)
            {
                if (default(T) != null)
                {
                    // 如果尝试将DBNull值转换为非可空类型,抛出异常
                    throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
                }
                return default;
            }
            return (T)val;
        }

        public T Get<T>(int index)
        {
            // 获取指定索引的参数值
            var parameter = oracleParameters[index];
            object val = parameter?.Value;
            if (val == DBNull.Value)
            {
                if (default(T) != null)
                {
                    // 如果尝试将DBNull值转换为非可空类型,抛出异常
                    throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
                }
                return default;
            }
            return (T)val;
        }
    }
}

添加 OracleDataAccessObject 类

复制代码
using Dapper;
using Oracle.ManagedDataAccess.Client;
using System.Data;

namespace DapperOracleDemo
{
    public class OracleDataAccessObject
    {
        private readonly string _ConnectionString;

        // 构造函数,初始化连接字符串
        public OracleDataAccessObject(string ConnectionString)
        {
            _ConnectionString = ConnectionString;
        }

        // 获取Oracle数据库连接
        private IDbConnection GetOracleConnection()
        {
            return new OracleConnection(_ConnectionString);
        }

        // 执行带参数的存储过程
        public dynamic OracleSProcWithParam(string sql, OracleDynamicParameters param)
        {
            // 使用using语句确保IDbConnection在使用后被正确关闭和释放
            using IDbConnection cnn = GetOracleConnection();
            CommandType? commandType = CommandType.StoredProcedure;
            // 执行存储过程
            return cnn.Execute(sql, param, null, null, commandType);
        }
    }
}

添加员工输入和输出 Dto

复制代码
namespace DapperOracleDemo
{
    public class EmployeeInputDto
    {
        public string NAME { get; set; }
        public string ADDRESS { get; set; }
        public string DEPARTMENT { get; set; }
        public string POSITION { get; set; }
    }
}

namespace DapperOracleDemo
{
    public class EmployeeOutputDto
    {
        public string EMP_ID { get; set; }
        public string ERROR { get; set; }
    }
}

using Oracle.ManagedDataAccess.Types;
namespace DapperOracleDemo
{
    public class SpReturnModel
    {
        public dynamic ID { get; set; }
        public OracleString ErrorMsg { get; set; }
    }
}

配置连接字符串

复制代码
static class Config
{
    public static string OracleDBConnectionString => "Data Source=192.168.29.1:1521/DEMODB;User Id=DEMO;Password=demo@123;";
    public static string SP_SAVE_EMPLOYEE_DETAILS = "DEMO.SAVE_EMPLOYEE_DETAILS";
}

添加 SaveEmployeeDetails() 方法

复制代码
static SpReturnModel SaveEmployeeDetails(EmployeeInputDto dto)
{
    var oraDao = new OracleDataAccessObject(Config.OracleDBConnectionString);
    var oracleParam = new OracleDynamicParameters();
    oracleParam.Add("V_NAME", OracleDbType.Varchar2, ParameterDirection.Input, dto.NAME);
    oracleParam.Add("V_ADDRESS", OracleDbType.Varchar2, ParameterDirection.Input, dto.ADDRESS);
    oracleParam.Add("V_DEPARTMENT", OracleDbType.Varchar2, ParameterDirection.Input, dto.DEPARTMENT);
    oracleParam.Add("V_POSITION", OracleDbType.Varchar2, ParameterDirection.Input, dto.POSITION);
    oracleParam.Add("O_EMP_ID", OracleDbType.Varchar2, ParameterDirection.Output, size: 20);
    oracleParam.Add("O_ERROR", OracleDbType.Varchar2, ParameterDirection.Output, size: 2000);
    var oracleQuery = Config.SP_SAVE_EMPLOYEE_DETAILS;
    oraDao.OracleSProcWithParam(oracleQuery, oracleParam);
    return GetSpOutParamResult(oracleParam, "O_EMP_ID");
}
static SpReturnModel GetSpOutParamResult(OracleDynamicParameters param, string idParam = "")
{
    SpReturnModel retMdl = new SpReturnModel()
    {
        ID = !string.IsNullOrEmpty(idParam) ? param.Get<dynamic>(idParam) : 0,
        ErrorMsg = param.Get<OracleString>("O_ERROR")
    };

    return retMdl;
}

测试应用程序

调用 SaveEmployeeDetails() 方法

复制代码
static void Main(string[] args)
{
    var inDto = new EmployeeInputDto
    {
        NAME = "SURYA RAJ GHIMIRE",
        ADDRESS = "KATHMANDU, NEPAL",
        DEPARTMENT = "RESEARCH & DEVELOPMENT",
        POSITION = "SOFTWARE ENGINEER"
    };
    var resp = SaveEmployeeDetails(inDto);
    var outDto = new EmployeeOutputDto
    {
        EMP_ID = resp.ID is null ? null : (string)resp.ID,
        ERROR = resp.ErrorMsg.ToString()
    };
    Console.WriteLine("Employee id: " + outDto.EMP_ID);
    Console.WriteLine("Error: " + outDto.ERROR);
    Console.ReadLine();
}

运行应用程序

运行您的 ASP.NET Core 应用程序并查看控制台上的输出。

结论

在本教程中,我们介绍了如何使用 Dapper 处理 ASP.NET Core 应用程序中 Oracle 存储过程的输出参数。通过遵循这些步骤,您可以有效地将 Oracle 存储过程集成到 .NET 应用程序中,利用 Dapper 的强大功能和简单性进行数据库操作。

相关推荐
牛奔13 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌18 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX19 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了19 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法20 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment20 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte21 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行1 天前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple1 天前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东1 天前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable