在前一篇文章「LINQPad + Oracle ODAC for Entity Framework」介紹了可以藉由LINQPad載入專案組件後就可以在LINQPad中操作LINQ Query,以達到程式實作前的測試操作,如果專案所使用的資料庫是 MS SQL Server 的話,在LINQPad中可以直接觀察EF所產出的 SQL Command,但要是專案所使用的資料庫是 Oracle,那麼在LINQPad就無法看到EF所產出的SQL Command,這種情況下就必須要回到Visual Studio中於偵錯模式下進行EF產出SQL Command 的觀察了,所以在本篇文章中將會說明幾種在Visual Studio的偵錯模式下觀察由Entity Framework所產出的SQL Command。
註:本篇將會著重於 Oracle ODAC for Entity Framework 情境下的解決方式,而有關使用 MS SQL Server 的專案,可以參考以下文章:
「Jerry - 我的Coding :查看LINQ Expression編譯後的SQL語法」
方法一:使用 ObjectQuery's ToTraceString Property
這方式的操作方式相當簡單,有兩種方式來使用這個方法,但都必須在偵錯模式下才能運作,其實這個方法的使用相當簡單,
例如,我們有以下的一個LINQ Query Expression
var query = from o in db.Orders
OrderBy o.OrderID
select o;
而在偵錯模式下去使用以下的程式,就可以輸出EF所產出的SQL Command
((System.Data.Objects.ObjectQuery)query).ToTraceString();
以下就來看看兩種實際應用的例子。
第一種方式:
在要執行偵錯的Method中去下中斷點,
進入偵錯模式,當程式執行到第27行之後,在「即時運算視窗」中去輸入「((System.Data.Objects.ObjectQuery)query).ToTraceString();」
輸入完後就按下「Enter」,就可以在「即時運算視窗」輸出由 EF所轉換的SQL Command,
第二種方式:
如果說,上面的那一種方式所得到的SQL Command不容易清楚的閱讀,我們也可以在Method中直接去執行輸出的程式,
接著進入偵錯模式,執行到第29行過後,將滑鼠游標移到「traceString」上面就可以看到輸出的SQL Command,
或是滑鼠游標移到「traceString」上面時,去點選IntelliSence所顯示的「放大鏡圖示」
文字視覺化顯示
複製產出的SQL Command並且貼到可以執行SQL Command的環境下執行,下圖的執行環境是「Navicat」
方法二:使用Entity Visualizer
有關這個Visual Studio套件的下載與使用,可以參考保哥的文章「介紹好用 Visual Studio 2010 擴充套件:Entity Visualizer」,文章中有詳細的說明,特別提醒一下,Entity Visualizer只能在 使用 .NET Framework 4.0 的專案中使用,所以只限定VS2010,如果是64-bit的環境,在保哥文章的評論區最後有提供 64-bit 的版本下載。
實際操作:
我們把剛才方法一在Method中所加入的程式給移除,並重新設定中斷點,
進入偵錯模式,當程式執行到第29行的時候,滑鼠游標移到 query 的變數上,出現IntelliSence後點擊「放大鏡」圖示,
General SQL
方法三:執行SQL指令
有些人是不喜歡在偵錯時才能去觀察EF產出的SQL Command,那如果系統已經上線或是非偵測模式下,那不就不能觀察產出的SQL嗎?
而使用LINQPad做LINQ Query Expression的操作測試,就無法即時產出Oracle的SQL Command……
因為Oracle並沒有MS SQL Server那樣有提供SQL Profiler的工具(MS SQL Server完整版才有, Express版沒有),雖然有相關的工具可以Profiler Oralce的SQL Command,但好用的要錢,不用錢的也不是很好用。
在LINQPad中去執行LINQ Query Expression:
接著在Navicat的Query中去執行以下的SQL Command:
select module,first_load_time ,sql_text
from v$sql
where
TO_DATE(first_load_time,'yyyy-mm-dd hh24:mi:ss') <= SYSDATE
order by first_load_time desc;
執行結果:
可以於查詢結果中看到第一筆資料,「MODULE」欄位是「LINQPad.exe」而其執行的SQL Command就記錄在「SQL_TEXT」欄位中
如果是在Visual Studio的偵測模式下執行,在Profiler的查詢結果如下:
是不是會覺得很雜亂呢?因為沒有去過濾「MODULE」欄位的值,執行 Profiler 的 SQL Command 時就會把所有的執行Profiler給撈出來,所以我們可以對 Profiler SQL Command去增加過濾MODULE的條件值,因為我的專案是使用 IISExpress 為程式開發伺服器,所以Profiler SQL Command就改成以下的內容:
select module,first_load_time ,sql_text
from v$sql
where
TO_DATE(first_load_time,'yyyy-mm-dd hh24:mi:ss') <= SYSDATE
and MODULE = 'iisexpress.exe'
order by first_load_time desc;
於Navicat中執行的查詢結果:
如果說,你的程式開發 Web 伺服器是使用 Visual Studio 所預設的,或是開發專案的網站已經附加到IIS伺服器的網站,我必須說…有時還真的找不到 MODULE 為「WebServer.exe」與 MODULE 為「w3wp.exe」的資料……
不過這個Profile SQL Command 倒是跟 LINQPad 蠻合得來,因為都可以正確無誤的把LINQPad 查詢給記錄起來,所以我會建議要在LINQPad中去觀察EF所產出的Oracle SQL Command,可以配合這個方法:
select module,first_load_time ,sql_text
from v$sql
where
TO_DATE(first_load_time,'yyyy-mm-dd hh24:mi:ss') <= SYSDATE
and MODULE = 'LINQPad.exe'
order by first_load_time desc;
其他方式:
MS SQL Server
如果專案使傭MS SQL Server而開發環境只有安裝MS SQL Server Express Management Studio,想要有SQL Profiler的功能,建議可以使用「AnjLab Sql Profiler」,這是一套免費的工具軟體,同樣提供與MS SQL Server SQL Profiler一樣的功能。
Oracle
如前面所說的,Oracle 資料庫如同比較少像 MS SQL Server SQL Profiler 同樣功能的監測工具,而有提同樣功能的工具也所費不貲,不過 Will 保哥有在他的文章裡分享一個工具:「Statement Tracer for Oracle」「Will - 保哥 : 介紹好用工具:Statement Tracer for Oracle」,經由 Google 查詢有關 Oracle 的 SQL Profiler 結果,查詢結果有一堆會說有哪些工具有提供相同的功能,但有的工具要錢不然就是是不出來。
藉由此篇來說明專案如果使用Oracle ODAC for Entity Framework 的情況下,如何取得由EF所產出的SQL Command,而使用MS SQL Server的專案就有最直接的支援工具可以善加利用。
延伸閱讀:
Visual Studio Magazine - Seeing the SQL Generated by LINQ to Entity Queries
http://visualstudiomagazine.com/blogs/tool-tracker/2011/11/seeing-the-sql.aspx
MKing's Blog - Oracle PL/SQL Profiler应用指南
http://blog.csdn.net/yzsind/article/details/351267
以上
讚,好用!!!,謝啦
回覆刪除Bibby兄, 還要向你多多學習哩
回覆刪除水!!
回覆刪除請問有什麼機制可以run time時期存放執行了哪些update/insert的指令?
Hello, 可以參考 Jarek Kowalski 所寫的「Tracing and Caching for Entity Framework available on MSDN Code Gallery (http://goo.gl/4gzp8)」以及「Logging SQL statements in Entity Framework/Code First (http://goo.gl/WXIuO)」.
刪除