当前位置: 首页 > news >正文

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
)
ASV_EMP_ID VARCHAR2 (10);
BEGIN-- GENERATE EMPLOYEE IDSELECT DEMO.EMP_SEQ.NEXTVAL INTO V_EMP_ID FROM DUAL;-- INSERT EMPLOYEE DETAILSINSERT 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 IDO_EMP_ID := V_EMP_ID;-- RESET ERROR OUTPUTO_ERROR := NULL;
EXCEPTIONWHEN OTHERS THENO_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 的强大功能和简单性进行数据库操作。

相关文章:

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

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

C++的动态内存分配

使用new/delete操作符在堆中分配/释放内存 //使用new操作符在堆中分配内存int* p1 new int;*p1 2234;qDebug() << "数字是&#xff1a;" << *p1;//使用delete操作符在堆中释放内存delete p1;在分配内存的同时初始化 //在分配内存的时初始化int* p2 n…...

【论文阅读】-- TSR-TVD:时变数据分析和可视化的时间超分辨率

TSR-TVD: Temporal Super-Resolution for Time-Varying Data Analysis and Visualization 摘要1 引言2 相关工作3 我们的循环生成方法3.1 损失函数3.2 网络架构 4 结果与讨论4.1 数据集和网络训练4.2 结果4.3 讨论 5 结论和未来工作致谢参考文献附录1 训练算法及优化2 网络分析…...

《web应用技术》第12次课后作业

1、了解servlet技术 Servlet(server applet)&#xff1a;运行在服务器的小程序&#xff0c;Servlet就是一个接口&#xff0c;定义了Java类被浏览器访问到的规则。将来我们自定义一个类&#xff0c;实现Servlet接口&#xff0c;复写方法。 Servlet本身不能独立运行&#xff0c…...

【初阶数据结构】深入解析带头双向循环链表:探索底层逻辑

&#x1f525;引言 本篇将介绍带头双向循环链表底层实现以及在实现中需要注意的事项&#xff0c;帮助各位在使用过程中根据底层实现考虑到效率上问题和使用时可能会导致的错误使用 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔…...

【面试干货】Java中的访问修饰符与访问级别

【面试干货】Java中的访问修饰符与访问级别 1、public2、protected3、默认&#xff08;没有访问修饰符&#xff09;4、private &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;访问修饰符用于控制类、变量、方法和构造器…...

Oracle最终还是杀死了MySQL

起因 大约15年前&#xff0c;Oracle收购了Sun公司&#xff0c;从而也拥有了MySQL&#xff0c;互联网上关于Oracle何时会“扼杀MySQL”的讨论此起彼伏。 当时流传着各种理论&#xff1a;从彻底扼杀 MySQL 以减少对 Oracle 专有数据库的竞争&#xff0c;到干掉 MySQL 开源项目&…...

【Python的随机数汇总】

​我们写python代码的时候&#xff0c;很少能用得上随机数&#xff0c;但是随机数有很多妙用。例如&#xff0c;在我们做测试数据集的时候&#xff0c;可以构建一个随机的dataframe&#xff1b; 或者在保存数据的时候&#xff0c;可以在每条数据前插入一列作为&#xff0c;不重…...

[状态压缩 广搜BFS]Saving Tang Monk

描述 《Journey to the West》(also 《Monkey》) is one of the Four Great Classical Novels of Chinese literature. It was written by Wu Chengen during the Ming Dynasty. In this novel, Monkey King Sun Wukong, pig Zhu Bajie and Sha Wujing, escorted Tang Monk to…...

Flutter 实现软鼠标

文章目录 前言一、如何实现&#xff1f;1、记录鼠标偏移2、MouseRegion获取偏移3、Transform移动图标 二、完整代码三、使用示例总结 前言 flutter在嵌入式系统中运行时&#xff0c;有可能遇到drm鼠标无法使用的情况&#xff0c;但鼠标事件却可以正常接收&#xff0c;此时如果…...

使用 MLRun 和 MinIO 设置开发机器

MLOps 之于机器学习&#xff0c;就像 DevOps 之于传统软件开发一样。两者都是一组旨在改善工程团队&#xff08;开发或 ML&#xff09;和 IT 运营 &#xff08;Ops&#xff09; 团队之间协作的实践和原则。目标是使用自动化来简化开发生命周期&#xff0c;从规划和开发到部署和…...

资质申请表详解:填写《建筑幕墙工程设计专项资质申请表》的要点

填写《建筑幕墙工程设计专项资质申请表》的要点如下&#xff0c;按照清晰、分点表示和归纳的方式整理&#xff0c;并参考了文章中的相关数字和信息&#xff1a; 一、封面 申报企业名称&#xff1a;按照工商营业执照内容填写全称&#xff0c;并加盖企业公章。填报日期&#xf…...

华为手机怎么找回删除的照片?掌握3个方法,恢复不是梦

由于误删、设备故障、软件更新等原因&#xff0c;我们有时可能会不慎丢失这些宝贵的照片。当面对空空如也的相册时&#xff0c;那种失落感无法言喻。华为手机该怎么找回删除的照片呢&#xff1f;但是&#xff0c;请不要绝望&#xff01;在科技的帮助下&#xff0c;我们可以采取…...

数据结构试题 20-21

真需要就死记吧 二叉树遍历-先序(非递归)【图解代码】_哔哩哔哩_bilibili 解释一下步骤&#xff1a; 一个循环为&#xff1a; 1.取节点 2.放右子树 3.放左子树 每次循环&#xff0c;都要从栈里取出一个节点 先放右子树&#xff0c;再放左子树 那这道题就是&#xff0c;先放1&am…...

vscode插件开发之 - TestController

TesController概要介绍 TestController 组件是用于实现自定义测试框架和集成测试结果的。它允许开发者定义自己的测试运行器&#xff0c;以支持在VSCode中运行和展示测试。以下是一些使用 TestController 组件的主要场景&#xff1a; 自定义测试框架&#xff1a;如果你正在开发…...

QBitArray使用详解

QBitArray使用详解 一、创建和初始化 QBitArray1.1 QBitArray默认构造1.2 QBitArray指定大小的构造1.3 QBitArray指定大小和初始值的构造 二、设置和访问位2.1 QBitArray设置单个位2.2 QBitArray访问单个位2.3 QBitArray使用下标操作符 三、设置所有位3.1 QBitArray将所有位设置…...

基于Python的自然语言处理项目 ChatTTS 推荐

**项目名称&#xff1a;ChatTTS**  ChatTTS是一个基于Python的自然语言处理项目&#xff0c;旨在实现一个简单的文本到语音转换系统。它使用深度学习技术&#xff0c;通过自然语言处理和语音合成算法&#xff0c;将文本转换为语音输出。  **项目介绍**&#xff1a;  Chat…...

论 To B 产品:从概念到市场实践

本文作者为 360 奇舞团产品经理 论 To B 产品&#xff1a;从概念到市场实践 To B 产品在商业世界中扮演着至关重要的角色。相较于面向消费者的To C市场&#xff0c;To B市场更专注于为其他企业提供产品和服务。理解和成功运营To B产品需要对其特定的市场需求和运作方式有深刻的…...

如何通过自定义模块DIY出专属个性化的CSDN主页?一招教你搞定!

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f4af;如何通过HTMLCSS自定义模板diy出自己的个性化csdn主页&#x…...

[BSidesCF 2020]Had a bad day1

看到页面有两个按钮 先随便点一个试一下&#xff0c;当我们点击之后发现url是有变动的 感觉url是有点东西的&#xff0c;可能是某种注入&#xff0c;先尝试一下sql注入&#xff0c;发现给出了报错 通过报错我们可以确定是文件包含漏洞&#xff0c;那我们试试php伪协议去读取一下…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用

阻止除自定义标签之外的所有标签 先输入一些标签测试&#xff0c;说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时&#xff08;如通过点击或键盘导航&…...

第2课 SiC MOSFET与 Si IGBT 静态特性对比

2.1 输出特性对比 2.2 转移特性对比 2.1 输出特性对比 器件的输出特性描述了当温度和栅源电压(栅射电压)为某一具体数值时,漏极电流(集电极电流...