C# 带refcursor参数查询的Dapper/Npgsql存储过程

C# 带refcursor参数查询的Dapper/Npgsql存储过程,c#,stored-procedures,dapper,npgsql,ref-cursor,C#,Stored Procedures,Dapper,Npgsql,Ref Cursor,我正在使用Dapper(我非常高兴),我知道如何访问前面提到的正常存储过程,但是,如何将Npgsqlrefcursor名称传递给进程(使用C#)?例如: 我有一个程序,看起来像: FUNCTION xx.getData( v_ref refcursor, v_id integer) RETURNS refcursor AS ... 如何为xx.getData指定参数 例如,如果getData只接受一个int类型的参数,那么我可以这样调用它: var data = cnn.Q

我正在使用Dapper(我非常高兴),我知道如何访问前面提到的正常存储过程,但是,如何将
Npgsql
refcursor
名称传递给进程(使用C#)?例如:

我有一个程序,看起来像:

FUNCTION xx.getData(
    v_ref refcursor,
    v_id integer)
  RETURNS refcursor AS
...
如何为
xx.getData
指定参数

例如,如果
getData
只接受一个int类型的参数,那么我可以这样调用它:

var data = cnn.Query<myType>("xx.getData", new {Id = 1}, 
        commandType: CommandType.StoredProcedure);

我在
System.DbType
中找不到要在查询中传递的正确类型

请注意,refcursor对应于在上一次调用中已打开的活动游标。换句话说,它不对应于存储过程,而是对应于结果集(可能但不一定从存储过程返回)


如果您真的需要发送一个refcursor,您需要的是
NpgsqlDbType.refcursor

下面是与Npgsql数据类型兼容的自定义动态参数。它将与输出refcursor参数一起工作

/// <summary>
/// Npgsql Dynamic Param for Dapper
/// </summary>
public class PgParam : SqlMapper.IDynamicParameters
{
    private static readonly Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
    private readonly Dictionary<string, ParamInfo> _parameters = new Dictionary<string, ParamInfo>();
    private List<object> templates;

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

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

    /// <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); }
    }

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

    /// <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(

        dynamic param
    )
    {
        if (param is object obj)
        {
            if (!(obj is PgParam subDynamic))
            {
                if (!(obj is IEnumerable<KeyValuePair<string, object>> dictionary))
                {
                    templates = templates ?? new List<object>();
                    templates.Add(obj);
                }
                else
                {
                    foreach (var kvp in dictionary)
                    {
                        Add(kvp.Key, kvp.Value);

                    }
                }
            }
            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(string name, object value = null, NpgsqlDbType? dbType = null, ParameterDirection? direction = null,int? size = null)
    {
        _parameters[name] = new ParamInfo
        {
            Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType,
            Size = size
        };
    }


    /// <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, true);
                        paramReaderCache[newIdent] = appender;
                    }
                }

                appender(command, template);
            }

        foreach (var param in _parameters.Values)
        {

            var add = !((NpgsqlCommand) command).Parameters.Contains(param.Name);
            NpgsqlParameter p;
            if (add)
            {
                p = ((NpgsqlCommand) command).CreateParameter();
                p.ParameterName = param.Name;
            }
            else
            {
                p = ((NpgsqlCommand) command).Parameters[param.Name];
            }

            var val = param.Value;
            p.Value = val ?? DBNull.Value;
            p.Direction = param.ParameterDirection;
            if (param.Size != null) p.Size = param.Size.Value;
            if (param.DbType != null) p.NpgsqlDbType = param.DbType.Value;
            if (add) command.Parameters.Add(p);
            param.AttachedParam = p;
        }
    }

    /// <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[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;
    }

    private class ParamInfo
    {
        public string Name { get; set; }

        public object Value { get; set; }

        public ParameterDirection ParameterDirection { get; set; }

        public NpgsqlDbType? DbType { get; set; }

        public int? Size { get; set; }

        public IDbDataParameter AttachedParam { get; set; }
    }
}
//
///用于Dapper的Npgsql动态参数
/// 
公共类PgParam:SqlMapper.IDynamicParameters
{
私有静态只读字典paramReaderCache=new Dictionary();
私有只读字典_参数=新字典();
私有列表模板;
/// 
///构造一个动态参数包
/// 
公共PgParam()
{
}
/// 
///构造一个动态参数包
/// 
///可以是匿名类型或DynamicParameters包
公共PgParam(对象模板)
{
添加动态图(模板);
}
/// 
///袋子里所有的参数的名字,用Get把它们拽出来
/// 
公共IEnumerable参数名称
{
获取{return}参数。选择(p=>p.Key);}
}
void SqlMapper.IDynamicParameters.AddParameters(IDbCommand命令,SqlMapper.Identity)
{
AddParameters(命令、标识);
}
/// 
///将一个充满参数的整个对象附加到动态
///例如:AddDynamicParams(新的{A=1,B=2})//将属性A和B添加到动态
/// 
/// 
公共无效添加动态内存(
动态参数
)
{
if(参数为对象obj)
{
如果(!(obj是PgParam子动态))
{
if(!(obj是IEnumerable字典))
{
模板=模板??新列表();
模板。添加(obj);
}
其他的
{
foreach(字典中的var kvp)
{
添加(kvp.Key,kvp.Value);
}
}
}
其他的
{
if(子动态参数!=null)
foreach(子动态参数中的var kvp)
_添加参数(kvp.Key,kvp.Value);
if(subDynamic.templates!=null)
{
模板=模板??新列表();
foreach(subDynamic.templates中的vart)templates.Add(t);
}
}
}
}
/// 
///将参数添加到此动态参数列表
/// 
/// 
/// 
/// 
/// 
/// 
public void Add(字符串名称,对象值=null,NpgsqlDbType?dbType=null,参数direction?direction=null,int?size=null)
{
_参数[名称]=新参数信息
{
Name=Name,Value=Value,ParameterDirection=direction??ParameterDirection.Input,DbType=DbType,
大小=大小
};
}
/// 
///在命令执行之前添加所有需要的参数
/// 
///执行前的原始命令
///有关查询的信息
受保护的void AddParameters(IDbCommand,SqlMapper.Identity)
{
如果(模板!=null)
foreach(模板中的var模板)
{
var newIdent=identity.ForDynamicParameters(template.GetType());
动作追加器;
锁定(paramReaderCache)
{
if(!paramReaderCache.TryGetValue(newIdent,out appender))
{
appender=SqlMapper.CreateParamInfoGenerator(newIdent、false、true);
paramReaderCache[newIdent]=追加器;
}
}
appender(命令、模板);
}
foreach(参数值中的变量参数)
{
var add=!((NpgsqlCommand)command.Parameters.Contains(param.Name);
npgsqlp参数;
如果(添加)
{
p=((NpgsqlCommand)command.CreateParameter();
p、 ParameterName=param.Name;
}
其他的
{
p=((NpgsqlCommand)command.Parameters[param.Name];
}
var val=参数值;
p、 Value=val??DBNull.Value;
p、 方向=参数参数方向;
如果(param.Size!=null)p.Size=param.Size.Value;
如果(param.DbType!=null)p.NpgsqlDbType=param.DbType.Value;
if(add)命令参数add(p);
param.AttachedParam=p;
}
}
/// 
///获取参数的值
/// 
/// 
/// 
///值note DBNull.value不返回,而是以null形式返回
公共T获取(字符串名称)
{
var val=_参数[name].AttachedParam.Value;
if(val==DBNull.Value)
{
如果(默认值(T)!=null)
抛出新的ApplicationException(“试图将DBNull强制转换为不可为Null的类型!”);
返回默认值(T);
}
返回(T)val;
}
私有类参数
/// <summary>
/// Npgsql Dynamic Param for Dapper
/// </summary>
public class PgParam : SqlMapper.IDynamicParameters
{
    private static readonly Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
    private readonly Dictionary<string, ParamInfo> _parameters = new Dictionary<string, ParamInfo>();
    private List<object> templates;

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

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

    /// <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); }
    }

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

    /// <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(

        dynamic param
    )
    {
        if (param is object obj)
        {
            if (!(obj is PgParam subDynamic))
            {
                if (!(obj is IEnumerable<KeyValuePair<string, object>> dictionary))
                {
                    templates = templates ?? new List<object>();
                    templates.Add(obj);
                }
                else
                {
                    foreach (var kvp in dictionary)
                    {
                        Add(kvp.Key, kvp.Value);

                    }
                }
            }
            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(string name, object value = null, NpgsqlDbType? dbType = null, ParameterDirection? direction = null,int? size = null)
    {
        _parameters[name] = new ParamInfo
        {
            Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType,
            Size = size
        };
    }


    /// <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, true);
                        paramReaderCache[newIdent] = appender;
                    }
                }

                appender(command, template);
            }

        foreach (var param in _parameters.Values)
        {

            var add = !((NpgsqlCommand) command).Parameters.Contains(param.Name);
            NpgsqlParameter p;
            if (add)
            {
                p = ((NpgsqlCommand) command).CreateParameter();
                p.ParameterName = param.Name;
            }
            else
            {
                p = ((NpgsqlCommand) command).Parameters[param.Name];
            }

            var val = param.Value;
            p.Value = val ?? DBNull.Value;
            p.Direction = param.ParameterDirection;
            if (param.Size != null) p.Size = param.Size.Value;
            if (param.DbType != null) p.NpgsqlDbType = param.DbType.Value;
            if (add) command.Parameters.Add(p);
            param.AttachedParam = p;
        }
    }

    /// <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[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;
    }

    private class ParamInfo
    {
        public string Name { get; set; }

        public object Value { get; set; }

        public ParameterDirection ParameterDirection { get; set; }

        public NpgsqlDbType? DbType { get; set; }

        public int? Size { get; set; }

        public IDbDataParameter AttachedParam { get; set; }
    }
}