Dapper完美兼容Oracle 執行存儲過程並返回結果
這個問題,困擾了我整整兩天。
剛剛用到Dapper的時候,感覺非常牛掰。特別是配合.net 4.0新特性dynamic,讓我生成泛型集合,再轉json一氣呵成。
不過,各種ORM總有讓人吐槽的地方。。。
比如,我之前在SqlServer上寫測試,搞封裝,沒有任何問題。CURD、批量操作、存儲過程、事物等。
可是以轉到Oracle上,就出問題了【喂~不是說好的支持Oracle的麼】
在寫Dapper+Oracle單元測試的前期,是沒有問題的,也就是說普通的Sql操作是沒有任何問題的。
然後,我寫到存儲過程的單元測試的時候,就蛋疼了。
因為原版采用的DbType數據類型枚舉。Sqlserver返回結果集並沒有輸出游標。
但是Oracle輸出結果集,就需要用游標了。那麼,這裡問題就來了。給OracleParameter設置參數類型,DbType並沒有Cursor游標類型。
關於Dapper的文檔也是不多,而且大部分都集中在SqlServer上,可能應為服務於.Net平台,比較側重於微軟的配套數據庫。
好吧,問題來了,那就解決。反正是開源的。源代碼都有。
先根據問題來搜索【我不喜歡用百度,因為百度搜出來一大堆不相關的東西,銅臭味太重。google在國內有無法訪問,我就選擇了Bing,結果效果還不錯。】
經過網上搜集,發現Dapper確實是支持Oracle的,但是對於調用Oracle存儲過程的內容卻沒有。
好吧,沒有的話,先自己分析分析。
既然是參數類型不支持,那麼換成支持的不就成了?
原版的是這樣的:
1 DynamicParameters dp = new DynamicParameters();
2 dp.Add("RoleId", "1");
3 dp.Add("RoleName", "", DbType.String, ParameterDirection.Output);
這是Dapper原版中,聲明parameter的部分,上面代碼紅色部分,就是指定參數類型。
在system.data.oracleclient 中,有OracleType這個枚舉有Cursor類型。
然後,去查看 DynamicParameters 類,如下圖:
可以看到,這個類,是實現了一個接口的。說明,原作者給我們預留了接口去自己實現其他內容。
繼續看看接口:
接口的內容很簡單,就是一個AddParameters方法。
那麼,可以確定,上面的猜測是對的。
我們直接擴展實現這個接口就可以了。如圖:
自己去創建一個實現了IDynamicParameters的類OracleDynamicParameters。
然後參照原作者提供的DynamicParameters類來實現這個接口。
最終修改版如下(代碼多,展開了直接貼到你的文件裡面):
View Code
ok,擴展寫完了,來一個單元測試,試一試:
1 /// <summary>
2 /// 執行帶參數存儲過程,並返回結果
3 /// </summary>
4 public static void ExectPro()
5 {
6 var p = new OracleDynamicParameters();
7 p.Add("beginTime", 201501);
8 p.Add("endTime", 201512);
9 p.Add("targetColumn", "tax");
10 p.Add("vCur", OracleDbType.RefCursor, ParameterDirection.Output);
11 using (IDbConnection conn = new OracleConnection(SqlConnOdp))
12 {
13 conn.Open();
14 var aa = conn.Query("p_123c", param: p, commandType: CommandType.StoredProcedure).ToList();
15 aa.ForEach(m => Console.WriteLine(m.C_NAME));
16 }
17 Console.ReadLine();
18 }
結果執行通過,並打印了首列的所有值。
那麼,Dapper的簡單擴展就完成了。
寫在後面
補充說明: 我用的Oracle驅動是ODP.NET,.net是4.0
這個ODP.NET的Oracle.DataAccess.dll推薦從你的目標服務器,復制回來,不要用本地的,反正我用本地的,就提示外部程序錯誤。猜測是版本問題或者是位數問題。