沒實際遇到,但接連兩次被問到使用 Dapper 如何從 Ref Cursor 讀取結果,看來上天已強烈暗示我沒 PO 文分享,趕緊補上以免逆天遭譴。

爬文找到的做法都是靠自訂 OracleDynamicParameter 處理 Ref Cursor 對應轉換,循著 Stackoverlow 討論找到一個 Gist 分享的現成版本,將 OracleDynamicParameter.cs 加入專案,便可使用 OracleDynamicParameters 物件 .Add("cursor_name", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output) 宣告 Ref Cursor 接收查詢結果。Ref Cursor 可用於 PL/SQL Script 或 Stored Procedure,記得改用 QueryMultiple().Read() 讀取結果,如果是 Stored Procedure,QueryMultiple() 時需指定 commandType: CommandType.StoredProcedure 參數。

註:上述的 Gist 版 OracleDynamicParameter 配合 Dapper 新版使用時,第 163 列需加上第三個參數 false:appender = SqlMapper.CreateParamInfoGenerator(newIdent, false, false);

測試成功!

附上完成範例:

        static void Main(string[] args)
        {
            using (var cn = new OracleConnection(cs))
            {
                var p = new OracleDynamicParameters();
                p.Add("n", 1234, OracleDbType.Decimal);
                p.Add("rc", 
                    dbType: OracleDbType.RefCursor,
                    direction: ParameterDirection.Output);
                
                //使用 T-SQL Script 測試 Ref Cursor
                var cmd = @"
declare 
begin 
open :rc for select :n as n, sysdate as d from dual;
end;";
                var m = cn.QueryMultiple(cmd, p);
                var data = m.Read();
                Console.WriteLine(JsonConvert.SerializeObject(data));
 
                /*
                --假設 Stored Procedure 如下
                create or replace procedure MyProc(
                 n NUMBER,
                 rc OUT SYS_REFCURSOR 
                )
                as
                begin
                  open rc
                   for select n as N, sysdate as D
                         from dual;
                end;
                 */
 
                //Stored Procedure記得指定commandType
                m = cn.QueryMultiple("MyProc", p, commandType: CommandType.StoredProcedure);
                data = m.Read();
                Console.WriteLine(JsonConvert.SerializeObject(data));
 
            }
            Console.Read();
        }
 

Comments

Be the first to post a comment

Post a comment