推薦功能強大的ORM Profiler,ORM問題追蹤的利器


應用LLBL Gen作為ORM框架訪問數據庫,數據讀寫不再與直接與SQL打交道。讀取銷售單代碼看起來是這樣的

public SalesOrderEntity GetSalesOrder(System.String RefNo, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList)
 {
            SalesOrderEntity _SalesOrder = new SalesOrderEntity(RefNo);
            using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
            {
                bool found = adapter.FetchEntity(_SalesOrder, prefetchPath, null, fieldList);
                if (!found) throw new Foundation.Common.RecordNotFoundException("Invalid Sales Order");
            }
            return _SalesOrder;
}

在界面層,以下面的代碼讀取銷售單

public override EntityBase2 LoadEntity(string customerNo)
 {
            ISalesOrderManager manager = ClientProxyFactory.CreateProxyInstance<ISalesOrderManager>();
            IPrefetchPath2 prefetchPath = new PrefetchPath2((int)Foundation.CustomerServices.EntityType.SalesOrderEntity);
            prefetchPath.Add(SalesOrderEntity.PrefetchPathSalesOrderDetails);
            SalesOrderEntity customer = manager.GetSalesOrder(customerNo, prefetchPath);
            return customer;
}

雖然這樣大大簡化了數據庫訪問方法。但同時,也帶來一些不方便的地方。比如,因為ORM是以動態SQL的方式,產生SQL語句,以參數傳遞的方式,無法追蹤到最終發送到SQL Server服務器的原始的SQL語句。其次,ORM產生的行為,與拼湊SQL有些不同。
例如,SalesOrderEntity order=new SalesOrderEntity();

order.Description=null;  => 產生的SQL是SalesOrder.Description is NULL

order.Description=string.Empty; => 產生的SQL是SalesOrder.Description=’’

也就是NULL和空字符串,是不同的含義。這種情況,在追蹤SQL查找問題時,極不容易察覺。

 

在沒有發布ORM Profile之前,要跟蹤LLBL產生的SQL,需要對配置文件作如下的設置,應用標准的.NET Trace機制

<system.diagnostics>
        <!-- LLBLGen Trace
            Trace Level:    0 - Disabled
                            3 - Info
                            4 - Verbose
        <switches>
            <add name="SqlServerDQE" value="0" />
            <add name="ORMGeneral" value="0" />
            <add name="ORMStateManagement" value="0" />
            <add name="ORMPersistenceExecution" value="0" />
        </switches>
        <trace autoflush="true">
            <listeners>
                <add name="textWriterTraceListener"
                     type="System.Diagnostics.TextWriterTraceListener"
                     initializeData="e:\erp\erp_log.txt" />
            </listeners>
        </trace>
        -->
    </system.diagnostics>

這種方法,將LLBL Gen生成的SQL 寫到文本文件,用於診斷產生問題的SQL語句。

借助於.NET 標准的Trace機制,我重寫了這樣的跟蹤,把LLBL Gen產生的SQL發送到指定的程序窗口中,代碼如下

public class ORMTraceListener : TraceListener
    {
        static Socket m_socClient;
        static bool m_server=false;

        static ORMTraceListener()
        {
            m_server = false;
            OnConnect("127.0.0.1", 8221);
        }
      
        public override void Write(string message)
        {
            if (!String.IsNullOrEmpty(message) && m_server&&NeedSend(message))
                OnSendData(message);
        }

        public override void WriteLine(string message)
        {
            if (!String.IsNullOrEmpty(message) && m_server && NeedSend(message))
                OnSendData(message+Environment.NewLine);
        }
}

經過這樣的設置,我們追蹤到的偽SQL,看起來像這樣

Generated Sql query: 

    Query: SELECT [Enterprise].[dbo].[User].[UserID] AS [UserId], [Enterprise].[dbo].[User].[UserName], [Enterprise].[dbo].[User].[PassWord], [Enterprise].[dbo].[User].[UserGroup], [Enterprise].[dbo].[User].[Suspended], [Enterprise].[dbo].[User].[DefaultLang], [Enterprise].[dbo].[User].[CreatedDate], [Enterprise].[dbo].[User].[CreatedBy], [Enterprise].[dbo].[User].[RevisedDate], [Enterprise].[dbo].[User].[RevisedBy], [Enterprise].[dbo].[User].[Email], [Enterprise].[dbo].[User].[AllCompany], [Enterprise].[dbo].[User].[AllCustomer], [Enterprise].[dbo].[User].[Allvendor], [Enterprise].[dbo].[User].[Buyer], [Enterprise].[dbo].[User].[SalesMan], [Enterprise].[dbo].[User].[AllReportView] FROM [Enterprise].[dbo].[User]  WHERE ( ( [Enterprise].[dbo].[User].[UserID] = @UserId1))

    Parameter: @UserId1 : String. Length: 10. Precision: 0. Scale: 0. Direction: Input. Value: "MIS".

這不能用於查詢分析器中直接執行,必須經過轉化。

 

這樣已經很接近於ORM Profile的目標了,官方推出的ORM Profile工具,對上面的目標進行更優化的設計。

image 

要讓你的程序啟動SQL跟蹤,只需要在程序啟動的地方,加入如下的語句

SD.Tools.OrmProfiler.Interceptor.InterceptorCore.Initialize("Enterprise Solution");

也可以反射調用上面的語句以啟動SQL跟蹤。在幫助文檔中有代碼,這里拷貝一份供您參考。

// Thanks to Craig Stuntz
private static void StartProfiler()
{
    if (AppSettings["ORMProfiler"] == "1")
    {
        System.Reflection.Assembly ormInterceptor = 
                System.Reflection.Assembly.Load("SD.Tools.OrmProfiler.Interceptor.EFv4");
        Type interceptor = ormInterceptor.GetType("SD.Tools.OrmProfiler.Interceptor.InterceptorCore");
        interceptor.InvokeMember("Initialize",
            System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.InvokeMethod |
            System.Reflection.BindingFlags.Static,
            null, null, new[] { "My.Web" }, System.Globalization.CultureInfo.CurrentUICulture);
    }
}

反射可以減少程序集編譯時的依賴,您只需要將下面的程序集復制到被跟蹤的應用程序目錄中即可

  • SD.Tools.OrmProfiler.Interceptor.dll (or for EFv4: SD.Tools.OrmProfiler.Interceptor.EFv4.dll)
  • SD.Tools.OrmProfiler.Shared.dll
  • SD.Tools.BCLExtensions.dll
  • SD.Tools.Algorithmia.dll


這樣,當前程序由LLBL Gen產生的SQL就會發送到ORM Profile主窗體中,以用於分析。

相對於問題查找,經常用到的是第二個選項卡Connections in chronological order

image

它顯示了數據庫連接和發送的SQL語句。這里可以看到,ORM Profile不僅僅可以追蹤SQL,還可以用於性能分析。比如這一句SQL,它返回了四筆數據,DB讀取時間是123.20ms。在下面的面板中,可以看到對SQL的各種分析。在SQL面板中,它顯示的SQL,與上面的相似。如果你想把這個SQL拷貝到查詢分析器中,結果如下

SELECT [Framework].[dbo].[User].[UserID] AS [UserId],
       [Framework].[dbo].[User].[UserName],
       [Framework].[dbo].[User].[PassWord],
       [Framework].[dbo].[User].[UserGroup],
       [Framework].[dbo].[User].[Suspended]
FROM   [Framework].[dbo].[User]
WHERE  (([Framework].[dbo].[User].[UserID] = 'MIS' /* @p1 */))

看到,這個工具已經將參數直接填充到SQL語句中,在查詢分析器中可直接執行,不作任何修改。

ORM Profile把每一次跟蹤會話叫做Snapshot,SQL文檔中,將這個詞語翻譯為快照,可理解為一個跟蹤會話,它可以保存在硬盤中,以便於再次分析。

對於Win Froms程序,在Main方法中調用Initialize,WPF程序,則在重寫的應用程序OnStartUp中調用Initialize,Web應用程序,在Global.asax中的Application_Start方法,調用Initialize。

在實際產品中,Profile會產生性能損耗,占用額外的內存和發送字節到ORM Profiler主程序中。在調用InterceptorCore.Initialize方法之后,跟蹤就開始。我們可以用方法

InterceptorCore.DisableMessageSending(); 停止跟蹤
也可再次啟用跟蹤,應用下面的方法
InterceptorCore.EnableMessageSending();


如果不希望每次都打開ORM Profile來攔截SQL跟蹤到的消息,我們可以在代碼中,把SQL跟蹤直接保存到文件中,在需要時,用ORM Profile打開跟蹤文件,以進行分析。下面的代碼來自於幫助文件,供您參考

// default ctor call, no filters, default analysis settings. You can specify filter settings and
// analysis settings in an overload of the ctor.
var snapshot = new Snapshot();
snapshot.Record();

// execute database activity here.
// …

// make sure the interceptor has flushed all messages over the named pipe.
InterceptorCore.Flush();

// messages arrive on another thread, so we have to wait here before all messages have arrived 
Thread.Sleep(200);
// after the pause, we can stop recording. 
snapshot.Stop();

// if you’ve specified filter settings in the ctor call, you have to do the following:
snapshot.ApplyFilters();
// if you want to perform analysis in code prior to saving the snapshot, you should
// uncomment the following line. NOTE: requires license file to be present.
// snapshot.ApplyAnalysis();

// the snapshot can now be saved:
string error=string.Empty;
snapshot.SaveToFile(filename, out error);

ORM Profile工具相當靈活,可用於編程以集成到自己的產品中,為你的系統穩定,性能提升添加高效率的工具。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM