如何在异常上使用参数值获取SQL

时间:2017-03-19 16:18:44

标签: nhibernate

很难相信,但我似乎无法找到一个直接的答案:当语句生成异常时,如何获取SQL语句包括参数值并且只有在它产生异常时。我知道如何为每个生成的SQL记录语句+参数,但这太过分了。但是,当有System.Data.SqlClient.SqlException时,它只提供SQL,而不是参数值。如何在我可以访问该数据的位置捕获它,以便我可以记录它?

2 个答案:

答案 0 :(得分:2)

根据对各种问题(不仅仅是我的)的一些回答,我拼凑了一些可以解决这个问题的问题。我认为它也可能对其他人有用,所以我在这里包括很多内容:

基本想法是

  1. 让NH记录所有查询,漂亮打印并使用参数值 in situ
  2. 抛出所有这些日志,除了异常之前的日志。
  3. 我使用Log4Net,设置如下:

    <?xml version="1.0"?>
    
    <log4net>
      <appender name="RockAndRoll" type="Util.PrettySqlRollingFileAppender, Util">
        <file type="log4net.Util.PatternString" >
          <conversionPattern value="%env{Temp}\\%property{LogDir}\\MyApp.log" />
        </file>
        <DatePattern value="MM-dd-yyyy" />
        <appendToFile value="true" />
        <immediateFlush value="true" />
        <rollingStyle value="Composite" />
        <maxSizeRollBackups value="10" />
        <maximumFileSize value="100MB" />
        <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%date %-5level %logger - %message%newline" />
        </layout>
      </appender>
    
      <appender name="ErrorBufferingAppender" type="log4net.Appender.BufferingForwardingAppender">
        <bufferSize value="2" />
        <lossy value="true" />
        <evaluator type="log4net.Core.LevelEvaluator">
          <threshold value="ERROR" />
        </evaluator>
        <appender-ref ref="RockAndRoll" />
        <Fix value="0" />
      </appender>
    
      <logger name="NHibernate.SQL">
        <additivity>false</additivity>
        <appender-ref ref="ErrorBufferingAppender" />
        <level value="debug" />
      </logger>
    
      <logger name="error-buffer">
        <additivity>false</additivity>
        <appender-ref ref="ErrorBufferingAppender" />
        <level value="debug" />
      </logger>
    
      <root>
        <level value="info" />
        <appender-ref ref="RockAndRoll" />
      </root>
    
    </log4net>
    

    NHibernate.SQL记录器将所有查询记录到ErrorBufferingAppender,这会将它们抛出并仅将最后一个保存在其缓冲区中。当我捕获异常时,我将ERROR级别的一行记录到记录器error-buffer,将其传递给ErrorBufferingAppender,因为它处于ERROR级别 - 将其与最后一个查询一起推送到RockAndRollRollingFileAppender

    我实现了一个名为RollingFileAppender的{​​{1}}的子类(我很乐意提供,如果有人感兴趣的话)从查询结尾获取参数并将它们替换为查询本身,它更具可读性。

答案 1 :(得分:0)

如果您使用查询数据库(因为您的问题中的标记存在建议),并且您的SQL方言/驱动程序依赖于ADO,那么您应该从失败的查询中获取GenericADOException

Message属性通常已包含参数值。

例如,执行以下失败的查询(假设您在DB中至少有一行):

var result = session.Query<Entity>()
    .Where(e => e.Name.Length / 0 == 1);

产生GenericADOException消息:

could not execute query  
[ select entity0_.Id as Id1_0_, entity0_.Name as Name2_0_ from Entity entity0_ where len(entity0_.Name)/@p0=@p1 ]  
  Name:p1 - Value:0  Name:p2 - Value:1

查询的两个文字01已经过参数化,它们的值包含在消息中(索引库不匹配:在hibernate查询中,它们是{{1}基于我的设置的SQL查询,它们最终基于1

因此,拥有它们没有什么特别之处。只需记录异常消息。

你是否错过了它,或者你确实在问别的什么? 在我看来,你的问题不够明确。您应该包含MVCE。它会更准确地告诉我在这种情况下你无法获得这些参数值。