如何在运行时访问(或生成)NHibernate Sql

时间:2012-03-19 13:29:04

标签: c# sql nhibernate hql

我认为标题是相当自我解释的,但要给出一点背景。

我一直在阅读这个问题,但它并不完全符合我的用例

Intercept-sql-statements-containing-parameter-values-generated-by-nhibernate

我遇到的问题是我只想在发生异常(或时间段过去)时注销生成的SQL。这是为了使我们能够在非常复杂的应用程序中对一些长时间运行的查询进行故障排除。我不想拦截并记录所有查询,因为我认为这会对性能产生影响。

在我想要记录它的时候,我有NHibernate使用的ICriteria对象,所以我正在寻找的是一种“虚拟”NHibernate对象,我可以触发这些ICriteria并获取SQL string(甚至包含参数占位符的SQL和参数列表)。

所以存在这样做的事情(我认为它要么非常简单而且我缺少某些东西,要么它很难以及其他人都不需要它。)

如果它不存在,那么创建实现目标的东西的最佳方法是什么,而无需手动构建SQL(我希望尽可能接近执行的SQL)。有没有办法直接进入NHibernate生成器并获取字符串?

添加此内容以使其更清晰。

我想这样做“事后”,而不是拦截每一个查询(由于性能问题)。我也不想使用Log4Net这样做,因为我需要将它记录在会话中。

我认为必须有一种方法来创建第二个NHibernate对象,它可能使用不同的驱动程序(一个不会进入数据库),这样我就可以实现拦截该对象的方法,并且不是持久存储到数据库的主要对象

3 个答案:

答案 0 :(得分:1)

如果您需要知道在有异常的情况下执行的查询,您可以使用检查异常的“数据”其他元素:

yourexception.Data["actual-sql-query"]

包含导致异常的查询。 在序数操作中,您可以使用名为“NHibernate.SQL”的记录器,这是获取查询文本的最可靠方式,因为其他“直接”方法取决于您查询NH的方式(ICriteria,Hql,QueryOver) ,LinqTONh,SOmeNewWayNotYetImplemented ...)所以拦截记录器通常会更好。

答案 1 :(得分:0)

默认情况下,如果在app / web config中启用以下log4net配置,NHibernate会在发生异常时记录查询

<log4net>
    <appender name="rollingFile" type="log4net.Appender.RollingFileAppender, log4net">
        <param name="File" value="Log\NHibernate\log.txt"/>
        <param name="AppendToFile" value="true"/>
        <param name="RollingStyle" value="Date"/>
        <param name="DatePattern" value="yyyy.MM.dd"/>
        <param name="StaticLogFileName" value="true"/>
        <layout type="log4net.Layout.PatternLayout, log4net">
            <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n"/>
        </layout>
    </appender>
    <root>
        <priority value="ERROR"/>
        <appender-ref ref="rollingFile"/>
    </root>
</log4net>

如果想从拦截器分配到某个全局变量或在拦截器中公开属性并在异常发生时记录它,如下所示

public class SessionManagerSQLInterceptor : EmptyInterceptor, IInterceptor
{
    //public string your property{ get; set; }  

    NHibernate.SqlCommand.SqlString IInterceptor.OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
    {
        NHSessionManager.Instance.NHibernateSQL = sql.ToString();
        //property = sql.ToString();
        //Or
        //AsignSqlToSomeGlobalVariable(sql.ToString());
        return sql;
    }
}

答案 2 :(得分:0)

如果您使用的是log4net,则可以使用BufferingForwardingAppender。这将允许您记录错误发生之前发生的可配置数量的日志事件(包括sql语句)。

  

此示例显示如何仅传递重要事件。一个   LevelEvaluator指定的阈值为WARN。这意味着   事件只会在具有WARN或.W等级的消息时传递   记录更高级别。最多512个(BufferSize)以前的消息   任何级别也将被提供以提供上下文信息。   未发送的邮件将被丢弃。

<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" >
    <bufferSize value="512" />
    <lossy value="true" />
    <evaluator type="log4net.Core.LevelEvaluator">
        <threshold value="WARN"/>
    </evaluator>
    <appender-ref ref="ConsoleAppender" />
</appender>

此处还有一篇博文:

http://www.beefycode.com/post/Log4Net-Tutorial-pt-8-Lossy-Logging.aspx