• 如何让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;
        }
    }

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

  • 相关阅读:
    浅析Java中使用AES对称加密步骤解析、SpringBoot如何实现AES加解密(秘钥、偏移量)、Java AES加解密工具类参考示例
    浅析Vue项目如何基于Vuex进行qiankun微前端应用间通信方案实践:子应用无vuex共用主应用store的方案(子应用里如何保证主应用store在子应用的响应式)、子应用有独立store与主应用store分离共存的方案
    浅析CSS中过渡transition学习:animation与transition的区别、过渡的4个属性及简写模式、过渡触发方式、过渡渐变(需绝对值)、如何使用硬件加速、过渡时间函数、过渡结束回调事件
    浅析Nginx配置获取客户端真实IP的proxy_set_header、XRealIP、$remote_addr、XForwardedFor、$proxy_add_x_forwarded_for分别是什么意思
    浅析Svelte介绍了解、如何看待 svelte 这个前端框架、svelte评测结论(存在一个阈值大小优势消失、适用简单应用场景又想要数据驱动方式)
    浅析什么是设计模式(套路)、为什么需要设计模式(最优解决方案)、前端常见设计模式(策略模式、发布订阅模式、装饰器模式、适配器模式、职责链模式、代理模式)
    浅析微前端qiankun的2种应用间通信方式(actions通信及shared通信、各自通信原理及实例代码)
    浅析mysql中查询使用 != 不等于会过滤掉null的情况及其原因分析和解决、IFNULL 函数用法及其使用需要注意的事项
    【Java】finally用法
    【Redis】单线程理解及可能影响性能的操作
  • 原文地址:https://www.cnblogs.com/hj4444/p/4976333.html
Copyright © 2020-2023  润新知