不用預先宣告強型別,查詢資料表後直接傳回 dynamic 是 Dapper 的強項,例如:var list = cn.Query("SELECT Col1,Col2 FROM T).ToList(); 將傳回 List<dynamic>,用 list.Fisrt().Col1 就能讀取欄位內容,簡潔又方便。

最近有個花式應用,想用通用函式接收 Dapper 查詢結果,自動列舉其中包含屬性(資料庫欄位)。一開始依循 System.Refelction 思維,想說用 GetType().GetProperties() 就可以搞定,不料踢到鐵板,Dapper 傳回的 dynamic 物件 .GetType() 結果為 null:

進一步追查,Dapper 傳回的 dynamic 骨子裡其實是個 DapperRow 型別,特別的是它實做了 IDictionary<string, object> 介面:

還記得既然要動態就動個痛快 - ExpandoObject介紹過 IDictionary<string, object> 的妙用,既然 DapperRow 是個 IDictionary<string, object> 一切好辦,轉型後用 .Keys 取回屬性清單,接下來就簡單了。

        static void Main(string[] args)
        {
            string sql = @"
SELECT 1 AS ColNum, SYSDATE AS ColDate, 'HELLO' AS ColString FROM DUAL UNION
SELECT 2 AS ColNum, SYSDATE AS ColDate, 'WORLD' AS ColString FROM DUAL
";
            using (var cn = new OracleConnection(cs))
            {
                var res = cn.Query(sql);
                StringBuilder sb = null;
                foreach (dynamic rec in res)
                {
                    var d = rec as IDictionary<string, object>;
                    if (sb == null)
                    {
                        sb = new StringBuilder(string.Join("\t", d.Keys.ToArray()));
                        sb.AppendLine();
                    }
                    sb.AppendLine(string.Join("\t",
                        d.Keys.Select(n => 
                            d[n] == null ? string.Empty : d[n].ToString()).ToArray()));
                }
                Console.WriteLine(sb.ToString());
 
                Console.Read();
            }
        }
        
 

經實測可成功列舉欄位名稱及內容:

COLNUM  COLDATE COLSTRING
1       2017/3/22 下午 09:07:30 HELLO
2       2017/3/22 下午 09:07:30 WORLD

最後,回到 DapperRow.GetType() 傳回 null 的謎團上,照理來說,GetType() 源自 Object 物件,查過 DapperRow 的原始碼並沒有覆寫 GetType(),想不出傳回 null 的理由。於是把問題丟上 stackoverflow,很快就有高手出面解惑,原來 DapperRow 實做了 DynamicMetaObject,攔截所有 dynamic 形式的成員存取,只要遇到非欄位名稱就傳回 null,因此不只 GetType(),呼叫 AsEnumerable() 也會傳回 null,所有謎團都解開了,結案!


Comments

# by 阿翰

謝謝大大 現在常用dapper 真的好用 專案編譯 運行效能 開發速度 都棒棒的

Post a comment