【问题标题】:How to get SQL with parameter values on an exception如何获取带有异常参数值的 SQL
【发布时间】:2017-08-10 20:47:18
【问题描述】:

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

【问题讨论】:

  • 帮助搜索时更容易找到它;异常消息仅包含值的问号,例如:VALUES (?, ?, ?, ?)
  • @BernhardHofmann:谢谢。我是否正确理解您添加评论以便其他人可以更轻松地找到此帖子?如果是这样,非常感谢。
  • 如果您以某种方式掌握了 DbCommand,您可以使用 this 问题中提到的参数构建查询。

标签: nhibernate


【解决方案1】:

根据对各种问题(不仅仅是我的问题)的大量回答,我拼凑出一些可以解决问题的方法。我认为它对其他人也可能有用,因此我在此处包含了很多内容:

基本思路是

  1. 让 NH 记录 所有 查询,打印精美并带有参数值原位
  2. 除异常前的日志外,将所有这些日志都抛出。

我用的是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 记录器将所有查询记录到ErrorBufferingAppenderErrorBufferingAppender 不断将它们丢弃并仅将最后一个保存在其缓冲区中。当我捕捉到一个异常时,我在错误级别记录一行到记录器error-buffer,它将它传递给ErrorBufferingAppender,因为它处于错误级别,所以将它与最后一个查询一起推送到RockAndRoll,我的RollingFileAppender

我实现了RollingFileAppender 的一个子类PrettySqlRollingFileAppender(如果有人感兴趣,我很乐意提供),它从查询末尾获取参数并将它们替换到查询本身中,使其更具可读性.

【讨论】:

    【解决方案2】:

    如果您使用 查询数据库(正如您问题上的标签所暗示的那样),并且您的 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 已被参数化,并且它们的值包含在消息中(索引基础不匹配:在休眠查询中,它们基于 1,而在使用我的设置进行 SQL 查询,它们最终以 0 为基础)。

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

    您只是错过了它,还是您确实在问其他问题?
    在我看来,你的问题不够明确。你应该包括一个MVCE。它会更准确地告诉我,在这种情况下你无法获得这些参数值。

    【讨论】:

    • 首先,感谢您的回复。接下来,是的,我正在使用 NH。最后,在这个特定的实例中,我得到一个 System.Data.SqlClient.SqlException,由 NHibernate.Util.ADOExceptionReporter 打印,它没有参数值。
    • 好吧,你的应用程序本身并不处理和记录它看起来的异常,并且仅依赖于 NHibernate 日志。然后为ADOExceptionReporter 激活Debug 日志级别,您应该拥有这些参数。
    • 再次感谢。我将 ADOExceptionReporter 的记录器设置为 DEBUG 级别,但它仍然没有输出值。
    • 如果没有MVCE,我无法为您提供更多帮助。我自己的案子没有你的问题。
    • 我看看能不能把东西放在一起。
    猜你喜欢
    • 2012-03-19
    • 2010-09-14
    • 2022-11-24
    • 2017-02-20
    • 2014-01-12
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多