如何让dapper支持oracle游标呢?

Dapper是一个轻型的ORM类。它有啥优点、缺点相信很多朋友都知道了,园里也有很多朋友都有相关介绍,这里就不多废话。

如果玩过Oracle都知道,存储过程基本都是通过游标返回数据的,但是dapper原生操作游标会报异常,具体异常信息因为现在没有环境就不截图了。

public FactoryPriceComparisonPublishItem GetTodayFactoryBasePricePushInfo(string weiXinId)
        {
            using (var cnn = Database.Connection("ERPDataBase"))
            {
                var p = new OracleDynamicParameters();
                p.Add("V_WEIXINID", weiXinId);
                p.Add("RetCursor", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);
                return cnn.Query<FactoryPriceComparisonPublishItem>("PKG_M_STEELMILL.GetFactoryPCPublishItem", param: p, commandType: CommandType.StoredProcedure).SingleOrDefault();
            }
        }

以上是实际项目的代码片段,通过游标获取查询数据。

那如何去解决这个游标问题呢?就是这个OracleDynamicParameters类,全部内容如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

using Dapper;
using Oracle.DataAccess.Client;

public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
    private static Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();

    private Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>();
    private List<object> templates;

    private class ParamInfo
    {

        public string Name { get; set; }

        public object Value { get; set; }

        public ParameterDirection ParameterDirection { get; set; }

        public OracleDbType? DbType { get; set; }

        public int? Size { get; set; }

        public IDbDataParameter AttachedParam { get; set; }
    }

    /// <summary>
    /// construct a dynamic parameter bag
    /// </summary>
    public OracleDynamicParameters()
    {
    }

    /// <summary>
    /// construct a dynamic parameter bag
    /// </summary>
    /// <param name="template">can be an anonymous type or a DynamicParameters bag</param>
    public OracleDynamicParameters(object template)
    {
        AddDynamicParams(template);
    }

    /// <summary>
    /// Append a whole object full of params to the dynamic
    /// EG: AddDynamicParams(new {A = 1, B = 2}) // will add property A and B to the dynamic
    /// </summary>
    /// <param name="param"></param>
    public void AddDynamicParams(
#if CSHARP30
            object param
#else
dynamic param
#endif
)
    {
        var obj = param as object;
        if (obj != null)
        {
            var subDynamic = obj as OracleDynamicParameters;
            if (subDynamic == null)
            {
                var dictionary = obj as IEnumerable<KeyValuePair<string, object>>;
                if (dictionary == null)
                {
                    templates = templates ?? new List<object>();
                    templates.Add(obj);
                }
                else
                {
                    foreach (var kvp in dictionary)
                    {
#if CSHARP30
                            Add(kvp.Key, kvp.Value, null, null, null);
#else
                        Add(kvp.Key, kvp.Value);
#endif
                    }
                }
            }
            else
            {
                if (subDynamic.parameters != null)
                {
                    foreach (var kvp in subDynamic.parameters)
                    {
                        parameters.Add(kvp.Key, kvp.Value);
                    }
                }

                if (subDynamic.templates != null)
                {
                    templates = templates ?? new List<object>();
                    foreach (var t in subDynamic.templates)
                    {
                        templates.Add(t);
                    }
                }
            }
        }
    }

    /// <summary>
    /// Add a parameter to this dynamic parameter list
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="dbType"></param>
    /// <param name="direction"></param>
    /// <param name="size"></param>
    public void Add(
#if CSHARP30
            string name, object value, DbType? dbType, ParameterDirection? direction, int? size
#else
string name, object value = null, OracleDbType? dbType = null, ParameterDirection? direction = null, int? size = null
#endif
)
    {
        parameters[Clean(name)] = new ParamInfo() { Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType, Size = size };
    }

    private static string Clean(string name)
    {
        if (!string.IsNullOrEmpty(name))
        {
            switch (name[0])
            {
                case ‘@‘:
                case ‘:‘:
                case ‘?‘:
                    return name.Substring(1);
            }
        }
        return name;
    }

    void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
        AddParameters(command, identity);
    }

    /// <summary>
    /// Add all the parameters needed to the command just before it executes
    /// </summary>
    /// <param name="command">The raw command prior to execution</param>
    /// <param name="identity">Information about the query</param>
    protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
        if (templates != null)
        {
            foreach (var template in templates)
            {
                var newIdent = identity.ForDynamicParameters(template.GetType());
                Action<IDbCommand, object> appender;

                lock (paramReaderCache)
                {
                    if (!paramReaderCache.TryGetValue(newIdent, out appender))
                    {
                        appender = SqlMapper.CreateParamInfoGenerator(newIdent, false, false);
                        paramReaderCache[newIdent] = appender;
                    }
                }

                appender(command, template);
            }
        }

        foreach (var param in parameters.Values)
        {
            string name = Clean(param.Name);
            bool add = !((OracleCommand)command).Parameters.Contains(name);
            OracleParameter p;
            if (add)
            {
                p = ((OracleCommand)command).CreateParameter();
                p.ParameterName = name;
            }
            else
            {
                p = ((OracleCommand)command).Parameters[name];
            }
            var val = param.Value;
            p.Value = val ?? DBNull.Value;
            p.Direction = param.ParameterDirection;
            var s = val as string;
            if (s != null)
            {
                if (s.Length <= 4000)
                {
                    p.Size = 4000;
                }
            }
            if (param.Size != null)
            {
                p.Size = param.Size.Value;
            }
            if (param.DbType != null)
            {
                p.OracleDbType = param.DbType.Value;
            }
            if (add)
            {
                command.Parameters.Add(p);
            }
            param.AttachedParam = p;
        }
    }

    /// <summary>
    /// All the names of the param in the bag, use Get to yank them out
    /// </summary>
    public IEnumerable<string> ParameterNames
    {
        get
        {
            return parameters.Select(p => p.Key);
        }
    }

    /// <summary>
    /// Get the value of a parameter
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns>The value, note DBNull.Value is not returned, instead the value is returned as null</returns>
    public T Get<T>(string name)
    {
        var val = parameters[Clean(name)].AttachedParam.Value;
        if (val == DBNull.Value)
        {
            if (default(T) != null)
            {
                throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");
            }
            return default(T);
        }
        return (T)val;
    }
}

希望对大家有所帮忙,谢谢!

时间: 2024-08-06 16:03:49

如何让dapper支持oracle游标呢?的相关文章

[转载]oracle游标概念讲解

原文URL:http://www.2cto.com/database/201203/122387.html ORACLE游标概念讲解 什么是游标?  ①从表中检索出结果集,从中每次指向一条记录进行交互的机制.      ②关系数据库中的操作是在完整的行集合上执行的.   由SELECT 语句返回的行集合包括满足该语句的WHERE 子句所列条件的所有行.由该语句返回完整的行集合叫做结果集.      应用程序,尤其是互动和在线应用程序,把完整的结果集作为一个单元处理并不总是有效的.      这些

Duang!危险的oracle游标

1.引言 SQL是面向集合的语言,其结果一般是集合量(含多条记录),而pl/sql的变量是标量,一组变量一次只能存放一条记录.很多时候查询结果的记录数是不确定的,无法提前声明足够的变量.于是引入了游标的概念,游标使得数据库操作更灵活,但同时也给黑客入侵数据库带来了机会.安华金和数据库安全实验室(DBSec Labs)基于游标的应用原理,本文讨论游标可能带来什么安全隐患以及如何应对这些安全隐患. 2.游标的分类 oracle数据库游标是Pl/sql执行DQL.DML等语句的时候,oracle在内存

BI测试工具之跨数据库数据对比,支持oracle,sqlserver

应用场景: 本周在进行SIT,我帮助仅有的一个测试妹妹对部分表进行数据质量验证,第一步需要做的就是比对source与stage表的table definition 与 数据内容的一致性. 本项目使用的是oracle作为DW,source是oracle,sqlserver和xls. 没有权限建立database link, 测试们常用的方法是比对总行数,然后如果数据集太大的话,则抽样比对,导出数据到xls,然后使用beyondcompare进行比对. 如果值出现不同,则需要查找出哪些行的值不同,最

Oracle GoldenGate (ogg) 11.2.1.0.20 是最后一个支持oracle db 10g的 ogg版本

参考原文: Oracle GoldenGate 11.2.1.0.22 Patch Set Availability (Doc ID 1669160.1) 该文章不做翻译,仅仅摘录其中有价值的信息,如下: Alert! OGG 11.2.1.0.22 is -not- available for Oracle Database 10g. Oracle GoldenGate 11.2.1.0.20 is the Terminal Release for support of Oracle Data

oracle 游标例子

CREATE OR REPLACE PROCEDURE PRC_WAP_ACTIVEUSERS(RETCODE OUT VARCHAR2) /*********************************************************** * 功能:WAP指标--活跃用户统计(分批提交) * 参数:RETCODE(返回编码:0000成功) * 作者: * 创建时间:2013-01-16 * 版本:1.0 * 修改人: * 修改时间: ********************

【翻译】Oracle游标详细说明

这篇文章是选取官方文档的部分章节翻译过来的,去除了原文中的例子,并在结尾补充了几个例子.有兴趣的朋友可以点击文章末尾的连接去阅读官方文档. 一.游标的定义 游标是指向专用SQL区域的指针,该区域存储有关处理特定SELECT或DML语句的信息.本章解释的游标是会话游标.会话游标存在于会话中直到会话结束.由PL/SQL创建和管理的游标称为隐式游标,由用户创建和管理的游标称为显式游标.你可以通过游标的属性获取任意会话游标的相关信息.通过查询动态性能视图V$OPEN_CURSOR,可以列出当前已经打开和

Oracle游标—for、loop、if结合应用

一.需求 什么时候会用到Oracle游标,以及其中的for.loop.if呢? 先看这样一个需求: 有一张学生授课表T_TEACHING,每个学生都有数门课程: 主键ID(自增) 课程号COURSE_ID 学号USER_ID 1 01 201501 2 02 201501 3 03 201501 4 01 201502 5 01 201503 6 01 201504 7 02 201504 ... ... ... 但是因为某些原因,导致有的学生课程不全(本应该每个学生都有3门课),应该如何把不全

Oracle游标循环更新数据案例

declare v_XTXMBH number; v_ZJZJZJRQ varchar2(40); cursor c_job is SELECT XT.XTXMBH AS XTXMBH, QJ.ZJZJZJRQ AS ZJZJZJRQ FROM XTXMXX XT, QJGLXX_ZQL_MID QJ WHERE XT.XTXMBH = QJ.XTXMBH AND XT.XTXMCLRQ >= '20120630' AND (QJ.ZJQHZJRQ IS NULL OR QJ.ZJZJZJRQ

oracle游标小试

有时候需要大面积的修改数据,这个时候用循环语句效率不高.而临时表又不能满足点对点修改的时候,游标似一种不错的选择(PS:好像游标也是为循环而生的吧) 现在有两张表 t1(ryid number,name nvarchar2(50),salary number,paydate date……)用来存员工每月的工资 t2(ryid number,paySalary number)每个月发的工资数目 现将t2中的paySalary添加到t1中 可以直接用update来实现: 现用oracle的for游标