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