3

実行された SQL を表示するように NHibernate を構成すると、想定どおりの動作をしますが、SQL 文字列を SQL Server Management Studio にコピー アンド ペーストする必要がある場合は、互換性を保つために大幅に再配置する必要があります。

これを解析してよりManagementStudioに適したSQLに再配置する独自のアプリケーションの開発に飛び込む前に、これは以前に行われたことがないことを再確認したいと思います-これに時間を費やして後で調べるのは嫌です.

NH で生成された準備済みステートメントをすぐに実行可能なものに変換する安価で実用的な方法はありますか?

前もって感謝します

4

2 に答える 2

7

nhibernateプロファイラーでこれを実行できることは知っていますが、これは無料のツールではありません。また、これを行うための無料の代替手段にも興味があります。

http://nhprof.com/

編集

log4net用のカスタムアペンダーがあり、実際にSQLNHibernateが吐き出すようにフォーマットするようです。私はそれを以下にリストされたブログで見ました:

http://gedgei.wordpress.com/2011/09/03/logging-nhibernate-queries-with-parameters/

以下は、上記のブログから取得し、Guidで動作するように変更したコードです。

/// <summary>
/// This log4net appender is used for outputting NHibernate sql statements in a sql management studio friendly format.
/// This means you should be able to copy the sql output from this appender and run it directly.  Normally in the NHibernate
/// output there is parameterized sql that must be manually edited to run it.
/// </summary>
public class NHibernateSqlAppender : ForwardingAppender
{
    private const string GuidRegex = @"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b";

    protected override void Append(LoggingEvent loggingEvent)
    {
        var loggingEventData = loggingEvent.GetLoggingEventData();

        if (loggingEventData.Message.Contains("@p"))
        {
            StringBuilder messageBuilder = new StringBuilder();

            string message = loggingEventData.Message;
            var queries = Regex.Split(message, @"command\s\d+:");

            foreach (var query in queries)
                messageBuilder.Append(ReplaceQueryParametersWithValues(query));

            loggingEventData.Message = messageBuilder.ToString();
        }

        base.Append(new LoggingEvent(loggingEventData));
    }

    public static string ReplaceQueryParametersWithValues(string query)
    {
        string returnQuery = Regex.Replace(query, @"@p\d+(?=[,);\s])(?!\s*=)", match =>
        {
            Regex parameterValueRegex = new Regex(string.Format(@".*{0}\s*=\s*(.*?)\s*[\[].*", match));
            return parameterValueRegex.Match(query).Groups[1].ToString();
        });

        //Place single quotes around all Guids in the sql string
        returnQuery = Regex.Replace(returnQuery, GuidRegex, "'$0'", RegexOptions.IgnoreCase);

        int parameterListIndex = returnQuery.LastIndexOf("@p0");

        if (parameterListIndex != -1)
        {
            //Truncate the paramter list off the end since we are substituting the actual values in the regular expression above
            //The -1 also cuts off the semicolon at the end
            return returnQuery.Substring(0, parameterListIndex).Trim();
        }

        return returnQuery.Trim();
    }
}

この出力をコンソールに送信する方法は次のとおりです。

<appender name="NHibernateSqlAppender" type="NHibernatePlayground.Custom.NHibernateSqlAppender, NHibernatePlayground">
    <appender-ref ref="console" />
</appender>

<root>
    <appender-ref ref="NHibernateSqlAppender" />
</root>

ノート:

これにより、実稼働システムでかなり重大なパフォーマンスの問題が発生するようです。私はこれを行うためのより良い方法をまだ見つけていませんが、これを使用している人はこれらのパフォーマンスの問題に注意してください

于 2012-06-13T14:45:36.643 に答える
1

私はしばらくこれを使用していませんが、インターセプターを使用することはあなたの基準に合うと思います。

using NHibernate;
using System.Diagnostics;

public class SqlStatementInterceptor : EmptyInterceptor
{
    public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
    {
        Trace.WriteLine(sql.ToString());
        return sql;
    }
}

クレジットはmindplay.dk ここのユーザーに送られます。

于 2012-06-14T11:59:54.787 に答える