Dapper完美兼容Oracle,执行存储过程,并返回结果集。
Dapper完美兼容Oracle,执行存储过程,并返回结果集。
这个问题,困扰了我整整两天。
刚刚用到Dapper的时候,感觉非常牛掰。特别是配合.net 4.0新特性dynamic,让我生成泛型集合,再转json一气呵成。
不过,各种ORM总有让人吐槽的地方。。。
比如,我之前在SqlServer上写测试,搞封装,没有任何问题。CURD、批量操作、存储过程、事物等。
可是以转到Oracle上,就出问题了【喂~不是说好的支持Oracle的么】
在写Dapper+Oracle单元测试的前期,是没有问题的,也就是说普通的Sql操作是没有任何问题的。
然后,我写到存储过程的单元测试的时候,就蛋疼了。
因为原版采用的DbType数据类型枚举。Sqlserver返回结果集并没有输出游标。
但是Oracle输出结果集,就需要用游标了。那么,这里问题就来了。给OracleParameter设置参数类型,DbType并没有Cursor游标类型。
关于Dapper的文档也是不多,而且大部分都集中在SqlServer上,可能应为服务于.Net平台,比较侧重于微软的配套数据库。
好吧,问题来了,那就解决。反正是开源的。源代码都有。
先根据问题来搜索【我不喜欢用百度,因为百度搜出来一大堆不相关的东西,铜臭味太重。google在国内有无法访问,我就选择了Bing,结果效果还不错。】
经过网上搜集,发现Dapper确实是支持Oracle的,但是对于调用Oracle存储过程的内容却没有。
好吧,没有的话,先自己分析分析。
既然是参数类型不支持,那么换成支持的不就成了?
原版的是这样的:
DynamicParameters dp = new DynamicParameters();
dp.Add("RoleId", "");
dp.Add("RoleName", "", DbType.String, ParameterDirection.Output);
这是Dapper原版中,声明parameter的部分,上面代码红色部分,就是指定参数类型。
在system.data.oracleclient 中,有OracleType这个枚举有Cursor类型。
然后,去查看 DynamicParameters 类,如下图:

可以看到,这个类,是实现了一个接口的。说明,原作者给我们预留了接口去自己实现其他内容。
继续看看接口:

接口的内容很简单,就是一个AddParameters方法。
那么,可以确定,上面的猜测是对的。
我们直接扩展实现这个接口就可以了。如图:

自己去创建一个实现了IDynamicParameters的类OracleDynamicParameters。
然后参照原作者提供的DynamicParameters类来实现这个接口。
最终修改版如下(代码多,展开了直接复制代码贴到你的文件里面):
public class OracleDynamicParameters : SqlMapper.IDynamicParameters {
private readonly DynamicParameters _dynamicParameters = new DynamicParameters();
private readonly List<OracleParameter> _oracleParameters = new List<OracleParameter>();
public void Add(string name, object value = null, DbType dbType = DbType.AnsiString, ParameterDirection? direction = null, int? size = null) {
_dynamicParameters.Add(name, value, dbType, direction, size);
}
public void Add(string name, OracleType oracleDbType, ParameterDirection direction) {
var oracleParameter = new OracleParameter(name, oracleDbType) { Direction = direction };
_oracleParameters.Add(oracleParameter);
}
public void Add(string name, OracleType oracleDbType, int size, ParameterDirection direction) {
var oracleParameter = new OracleParameter(name, oracleDbType, size) { Direction = direction };
_oracleParameters.Add(oracleParameter);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity) {
((SqlMapper.IDynamicParameters)_dynamicParameters).AddParameters(command, identity);
var oracleCommand = command as OracleCommand;
if (oracleCommand != null) {
oracleCommand.Parameters.AddRange(_oracleParameters.ToArray());
}
}
public T Get<T>(string parameterName) {
var parameter = _oracleParameters.SingleOrDefault(t => t.ParameterName == parameterName);
if (parameter != null)
return (T)Convert.ChangeType(parameter.Value, typeof(T));
return default(T);
}
public T Get<T>(int index) {
var parameter = _oracleParameters[index];
if (parameter != null)
return (T)Convert.ChangeType(parameter.Value, typeof(T));
return default(T);
}
}
public sealed class DbString {
public DbString() { Length = -; }
public bool IsAnsi { get; set; }
public bool IsFixedLength { get; set; }
public int Length { get; set; }
public string Value { get; set; }
public void AddParameter(IDbCommand command, string name) {
if (IsFixedLength && Length == -) {
throw new InvalidOperationException("If specifying IsFixedLength, a Length must also be specified");
}
var param = command.CreateParameter();
param.ParameterName = name;
param.Value = (object)Value ?? DBNull.Value;
if (Length == - && Value != null && Value.Length <= ) {
param.Size = ;
}
else {
param.Size = Length;
}
param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);
command.Parameters.Add(param);
}
}
ok,扩展写完了,来一个单元测试,试一试:
/// <summary>
/// 执行带参数存储过程,并返回结果
/// </summary>
public static void ExectPro()
{
var p = new OracleDynamicParameters();
p.Add("beginTime", );
p.Add("endTime", );
p.Add("targetColumn", "tax");
p.Add("vCur", OracleDbType.RefCursor, ParameterDirection.Output);
using (IDbConnection conn = new OracleConnection(SqlConnOdp))
{
conn.Open();
var aa = conn.Query("p_123c", param: p, commandType: CommandType.StoredProcedure).ToList();
aa.ForEach(m => Console.WriteLine(m.C_NAME));
}
Console.ReadLine();
}
结果执行通过,并打印了首列的所有值。
那么,Dapper的简单扩展就完成了。
写在后面
补充说明: 我用的Oracle驱动是ODP.NET,.net是4.0
这个ODP.NET的Oracle.DataAccess.dll推荐从你的目标服务器,复制回来,不要用本地的,反正我用本地的,就提示外部程序错误。猜测是版本问题或者是位数问题。
相关参考文章
http://stackoverflow.com/questions/6212992/using-dapper-with-oracle
https://stackoverflow.com/questions/15943389/using-dapper-with-oracle-user-defined-types
Dapper完美兼容Oracle,执行存储过程,并返回结果集。的更多相关文章
- oracle创建存储过程并返回结果集(附C#调用代码)
使用存储过程中,最常用的莫过于查询数据表,并返回结果集. 在SQL SERVER 中,这类操作最简单,通过简单的select * from xx 即可完成.但是在Oracle中并不支持这种写法,那么我 ...
- oracle的存储过程如何返回结果集
CREATE OR REPLACE PACKAGE pkg_test AS TYPE myrctype IS REF CURSOR; PROCEDURE get (p_id NUM ...
- 存储过程不返回记录集导致ADO程序出错
HRESULT _hr = get_adoEOF(&_result); IsEOF()函数如下:其中ADOCG::_RecordsetPtr m_pRecordset; BOOL IsEOF( ...
- C#获取执行存储过程的" 返回值"代码
以下是C#代码: /// <summary> /// 执行存储过程,返回" 返回值" /// </summary> /// <param name=& ...
- 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值
关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...
- Oracle中函数/过程返回结果集的几种方式
原文 Oracle中函数/过程返回结果集的几种方式 Oracle中函数/过程返回结果集的几种方式: 以函数return为例,存储过程只需改为out参数即可,在oracle 10g测试通过. ...
- [转]Oracle 调用存储过程并显示结果集 Oracle.DataAccess.Client OracleDbType.RefCursor
本文转自:http://liye9801.blog.163.com/blog/static/6019703200901244448950/ 今天学习了一个Oracle中的存储过程,一开始便被如果返回结 ...
- .net 使用oracle 的存储过程有返回值也有数据集(游标)
public void GetData(string username, string userip, string userkey, string userareaid, string ypid, ...
- 转:Entity FrameWork利用Database.SqlQuery<T>执行存储过程并返回参数
public IEnumerable<Statistic> GetStatistics(IEnumerable<Guid> itemIds) { var ctx = new D ...
随机推荐
- [Java] JSP笔记 - Filter 过滤器
一.什么是Web过滤器 Servlet API 很久以前就已成为企业应用开发的基石,而 Servlet 过滤器则是对 J2EE 家族的相对较新的补充. Servlet 过滤器是可插入的 Web 组件, ...
- Node.js之路【第三篇】NodeJS异步实现
NodeJS异步实现 Node.js异步编程的直接体现就是回调,它依托于回调来实现,但不能说使用了回调他就是异步了 回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都 ...
- 第一章 --- 关于Javascript 设计模式 之 单例模式
首先我们对单例模式先进行理论上的讲解,接下来,我们再通过具体的代码示例,来讲解,这个单例模式的使用场景和这种模式的优缺点 (这个系列的所有关于设计模式的都是面向Javascript) 一.理论定义: ...
- github免密码设置
在创建好了github账号之后,我们可以新建自己的github项目.然而,我们在本地代码升级维护的过程中,涉及到git操作的时候并不是想每次都重新输入密码.这个时候我们需要使用ssh和私钥(公钥)来方 ...
- C# Activator.CreateInstance()方法使用
C#在类工厂中动态创建类的实例,所使用的方法为: 1. Activator.CreateInstance (Type) 2. Activator.CreateInstance (Type, Objec ...
- [译]Object.getPrototypeOf
原文 概要 返回指定object的prototype. 语法 Object.getPrototypeOf(object) 参数 object 要返回原型的对象. 描述 当object参数不是一个对象的 ...
- mysql数据库存储路径更改 数据文件位置
使用了VPS一段时间之后发现磁盘空间快满了.本人的VPS在购买的时候买了500gb的磁盘,提供商赠送了20GB的高性能系统磁盘.这样系统就有两个磁盘空间了.在初次安装mysql 的时候将数据库目录安装 ...
- Excel—利用散点图计算相关系数
1.建立数组 2.创建散点图. 3.添加趋势线. 4.设立为线性函数,勾选显示公式.显示R^2值,R即为相关系数. 5. 备注:此外也可以使用=CORREL()函数对相关系数进行求值.其结果是一致的.
- href="javascript:;" 作用
<a href="javascript:;" onclick="doExport(this)" class="easyui-linkbutton ...
- Maven把自己的包部署到远程仓库
1,配置项目的POM文件 <dependencyManagement> </dependencies> </dependency> ...... </depe ...