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

相关推荐
摇滚侠3 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
程序员小凯5 小时前
Spring Boot测试框架详解
java·spring boot·后端
CsharpDev-奶豆哥6 小时前
ASP.NET中for和foreach使用指南
windows·microsoft·c#·asp.net·.net
你的人类朋友6 小时前
什么是断言?
前端·后端·安全
程序员小凯7 小时前
Spring Boot缓存机制详解
spring boot·后端·缓存
TiAmo zhang7 小时前
SQL Server 2019实验 │ 数据库和表的创建、修改与删除
数据库·oracle
i学长的猫8 小时前
Ruby on Rails 从0 开始入门到进阶到高级 - 10分钟速通版
后端·ruby on rails·ruby
FuckPatience8 小时前
前后端分离项目部署完成后 前后端交互过程
vue.js·asp.net
用户21411832636028 小时前
别再为 Claude 付费!Codex + 免费模型 + cc-switch,多场景 AI 编程全搞定
后端
茯苓gao8 小时前
Django网站开发记录(一)配置Mniconda,Python虚拟环境,配置Django
后端·python·django