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 的强大功能和简单性进行数据库操作。

相关推荐
掘金者阿豪8 分钟前
听书别再被会员和广告打断:把NAS变成自己的私人有声图书馆
后端
拉长的苗条41 分钟前
细说 ASP.NET Cache 及其高级用法
后端·asp.net
一路向北North44 分钟前
Spring Security OAuth2.0(19):JWT令牌
java·后端·spring
用户6757049885021 小时前
Beanstalkd 实战指南:原来延迟队列、异步任务可以如此简单丝滑!
后端·消息队列
醉熏的斑马1 小时前
ASP.Net MVC3 】使用Moq让单元测试变得更简单
单元测试·log4j·asp.net
oradh2 小时前
Oracle DG主备架构的基本维护操作总结
数据库·oracle·架构·dg主备架构的基本维护操作总结
MacroZheng2 小时前
给Claude Code装上这款炫酷的HUD插件,状态信息就一目了然了!
java·人工智能·后端
达达尼昂2 小时前
编码智能体中的模型选择与执行深度
人工智能·后端·程序员
用户6757049885022 小时前
写了 6 年 Go ,我终于领悟到了泛型的真正威力!
后端·go
MegatronKing2 小时前
AI时代我们要如何玩抓包测试
前端·后端·测试