将 Dapper 与返回游标的 Oracle 存储过程结合使用

发布于 2024-12-04 07:32:00 字数 426 浏览 1 评论 0原文

如何将 Dapper 与返回游标的 Oracle 存储过程一起使用?

var p = new DynamicParameters();
p.Add("foo", "bar");
p.Add("baz_cursor", dbType: DbType.? , direction: ParameterDirection.Output);

这里,DbType是System.Data.DbType,它没有Cursor成员。我尝试过使用 DbType.Object,但这不适用于 OracleClient 和 OracleDataAcess。

使用 OracleType 或 OracleDbType 的可能方法是什么?

How would one go about using Dapper with Oracle stored procedures which return cursors?

var p = new DynamicParameters();
p.Add("foo", "bar");
p.Add("baz_cursor", dbType: DbType.? , direction: ParameterDirection.Output);

Here, the DbType is System.Data.DbType which does not have a Cursor member. I've tried using DbType.Object but that does not work with both OracleClient and OracleDataAcess.

What would be a possible way to use OracleType or OracleDbType instead?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦年海沫深 2024-12-11 07:32:00

感谢这里的解决方案。我使用简单的 DynamicParameter 装饰器用更少的代码实现了同样的效果:

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 = null, ParameterDirection? direction = null, int? size = null)
    {
        dynamicParameters.Add(name, value, dbType, direction, size);
    }

    public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
    {
        var oracleParameter = new OracleParameter(name, oracleDbType, 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());
        }
    }
}

Thanks for the solution here. I achieved the same thing with a little less code using a simple DynamicParameter decorator:

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 = null, ParameterDirection? direction = null, int? size = null)
    {
        dynamicParameters.Add(name, value, dbType, direction, size);
    }

    public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
    {
        var oracleParameter = new OracleParameter(name, oracleDbType, 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());
        }
    }
}
ペ泪落弦音 2024-12-11 07:32:00

您必须实现:

 public interface IDynamicParameters
 {
    void AddParameters(IDbCommand command, Identity identity);
 }

然后在 AddParameters 回调中,您将 IDbCommand 转换为 OracleCommand 并添加数据库特定参数。

You would have to implement:

 public interface IDynamicParameters
 {
    void AddParameters(IDbCommand command, Identity identity);
 }

Then in the AddParameters callback you would cast the IDbCommand to an OracleCommand and add the DB specific params.

别把无礼当个性 2024-12-11 07:32:00

this 类添加到您的项目中

,您的代码应如下所示:-

        var p = new OracleDynamicParameters();
        p.Add("param1", pAuditType);
        p.Add("param2", pCommnId);
        p.Add("outCursor", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);

        using (var multi = cnn.QueryMultiple("procedure_name", param: p, commandType: CommandType.StoredProcedure))
        {
            var data = multi.Read();
            return data;
        }

Add this class to your project

and your code should like below :-

        var p = new OracleDynamicParameters();
        p.Add("param1", pAuditType);
        p.Add("param2", pCommnId);
        p.Add("outCursor", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);

        using (var multi = cnn.QueryMultiple("procedure_name", param: p, commandType: CommandType.StoredProcedure))
        {
            var data = multi.Read();
            return data;
        }
听风念你 2024-12-11 07:32:00

只是为了详细说明萨姆的建议,这就是我的想法。请注意,此代码很脆弱,现在仅适用于 Oracle。

修改Dapper 1.7

void SqlMapper.IDynamicParameters.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);
                        paramReaderCache[newIdent] = appender;
                    }
                }

                appender(command, template);
            }
        }

        foreach (var param in parameters.Values)
        {
            string name = Clean(param.Name);
            bool add = !((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Contains(name);
            Oracle.DataAccess.Client.OracleParameter p;
            if(add)
            {
                p = ((Oracle.DataAccess.Client.OracleCommand)command).CreateParameter();
                p.ParameterName = name;
            } else
            {
                p = ((Oracle.DataAccess.Client.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.DbType = param.DbType.Value;    
            }
            if (add)
            {
                if (param.DbType != null && param.DbType == DbType.Object)
                {
                    p.OracleDbType = Oracle.DataAccess.Client.OracleDbType.RefCursor;
                    ((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
                }
                else
                {
                    ((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
                }                       
            }
            param.AttachedParam = p;
        }
    }

测试代码

class Program
{
    static void Main(string[] args)
    {
        OracleConnection conn = null;
        try
        {
            const string connString = "DATA SOURCE=XE;PERSIST SECURITY INFO=True;USER ID=HR;PASSWORD=Adv41722";

            conn = new OracleConnection(connString);
            conn.Open();


            var p = new DynamicParameters();
            p.Add(":dep_id", 60);
            p.Add(":employees_c", dbType: DbType.Object, direction: ParameterDirection.Output);
            p.Add(":departments_c", dbType: DbType.Object, direction: ParameterDirection.Output);
            // This will return an IEnumerable<Employee> // How do I return both result?
            var results = conn.Query<Employee>("HR_DATA.GETCURSORS", p, commandType: CommandType.StoredProcedure);



        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
            throw;
        }
        finally
        {
            if (conn != null && conn.State == ConnectionState.Open)
            {
                conn.Close();
            }                
        }
        Console.WriteLine("Fininhed!");
        Console.ReadLine();
    }
}

class Employee
{
    public int Employee_ID { get; set; }
    public string FIRST_NAME { get; set; }
    public string LAST_NAME { get; set; }
    public string EMAIL { get; set; }
    public string PHONE_NUMBER { get; set; }
}

Just to elaborate on Sams suggestion here's what I came up with. Note that this code is brittle and is now just for Oracle.

Modified Dapper 1.7

void SqlMapper.IDynamicParameters.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);
                        paramReaderCache[newIdent] = appender;
                    }
                }

                appender(command, template);
            }
        }

        foreach (var param in parameters.Values)
        {
            string name = Clean(param.Name);
            bool add = !((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Contains(name);
            Oracle.DataAccess.Client.OracleParameter p;
            if(add)
            {
                p = ((Oracle.DataAccess.Client.OracleCommand)command).CreateParameter();
                p.ParameterName = name;
            } else
            {
                p = ((Oracle.DataAccess.Client.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.DbType = param.DbType.Value;    
            }
            if (add)
            {
                if (param.DbType != null && param.DbType == DbType.Object)
                {
                    p.OracleDbType = Oracle.DataAccess.Client.OracleDbType.RefCursor;
                    ((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
                }
                else
                {
                    ((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
                }                       
            }
            param.AttachedParam = p;
        }
    }

Test code

class Program
{
    static void Main(string[] args)
    {
        OracleConnection conn = null;
        try
        {
            const string connString = "DATA SOURCE=XE;PERSIST SECURITY INFO=True;USER ID=HR;PASSWORD=Adv41722";

            conn = new OracleConnection(connString);
            conn.Open();


            var p = new DynamicParameters();
            p.Add(":dep_id", 60);
            p.Add(":employees_c", dbType: DbType.Object, direction: ParameterDirection.Output);
            p.Add(":departments_c", dbType: DbType.Object, direction: ParameterDirection.Output);
            // This will return an IEnumerable<Employee> // How do I return both result?
            var results = conn.Query<Employee>("HR_DATA.GETCURSORS", p, commandType: CommandType.StoredProcedure);



        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
            throw;
        }
        finally
        {
            if (conn != null && conn.State == ConnectionState.Open)
            {
                conn.Close();
            }                
        }
        Console.WriteLine("Fininhed!");
        Console.ReadLine();
    }
}

class Employee
{
    public int Employee_ID { get; set; }
    public string FIRST_NAME { get; set; }
    public string LAST_NAME { get; set; }
    public string EMAIL { get; set; }
    public string PHONE_NUMBER { get; set; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文