• 推荐功能强大的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工具相当灵活,可用于编程以集成到自己的产品中,为你的系统稳定,性能提升添加高效率的工具。

  • 相关阅读:
    机器学习【工具】:Numpy
    机器学习【算法】:KNN近邻
    【笔记】:字典内部剖析
    【笔记】:谁偷了我的内存?
    什么是RESTful框架
    音频下载服务
    【模块】:Requests(二)
    【模块】:Weakref
    异步Web服务(二)
    【Win10】UAP/UWP/通用 开发之 RelativePanel
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/2696336.html
Copyright © 2020-2023  润新知