Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain NHibernate generated SQL in code at runtime?

I know you can view the NHibernate generated SQL by hooking it up to log4net or piping it out to the console ("show_sql" option), but is there any way to obtain the generated SQL in code at runtime?

What I would like to be able to do is take an ICriteria object (or IQuery) and dump the generated SQL to the screen or custom log (not log4net). Something like...

var sql = criteria.GetGeneratedSql() // Wishful thinking

Can something like this be done?


EDIT: Thanks to DanP's excellent find of a "Hibernate Criteria to SQL Translation" class for Java, I took a first crack at porting this to NHibernate. Seems to work for simple cases, but definitely could use some improvement (i.e. error handling, etc.)

using NHibernate.Engine;
using NHibernate.Hql.Ast.ANTLR;
using NHibernate.Impl;
using NHibernate.Loader;
using NHibernate.Loader.Criteria;
using NHibernate.Persister.Entity;

public class HibernateHqlAndCriteriaToSqlTranslator
{
    public HibernateHqlAndCriteriaToSqlTranslator() { }

    public ISessionFactory SessionFactory { get; set; }

    public string ToSql(ICriteria criteria)
    {
        var c = (CriteriaImpl) criteria;
        var s = (SessionImpl)c.Session;
        var factory = (ISessionFactoryImplementor)s.SessionFactory;
        String[] implementors = factory.GetImplementors(c.EntityOrClassName);
        var loader = new CriteriaLoader(
            (IOuterJoinLoadable)factory.GetEntityPersister(implementors[0]),
            factory, 
            c, 
            implementors[0], 
            s.EnabledFilters);

        return ((OuterJoinLoader)loader).SqlString.ToString();
    }

    public string ToSql(string hqlQueryText)
    { 
        if (!String.IsNullOrEmpty(hqlQueryText))
        {
            var translatorFactory = new ASTQueryTranslatorFactory();
            var factory = (ISessionFactoryImplementor) this.SessionFactory;
            var translator = translatorFactory.CreateQueryTranslator(
                hqlQueryText, 
                hqlQueryText, 
                new Dictionary<String, IFilter>(), 
                factory);
            translator.Compile(new Dictionary<String, String>(), false);
            return translator.SQLString;
        }

        return null;
    }
}
like image 265
WayneC Avatar asked Jul 20 '10 16:07

WayneC


People also ask

How do you debug NHibernate?

You just need to choose New Breakpoint from the Debug menu and then Break at function... (or Ctrl + B) and in the Function box type NHibernate. Impl. SessionImpl.

How do I get SQL query from NHibernate?

Translating NHibernate LINQ expression tree to SQL without executing query against database server is trick we can use to investigate generated SQL when writing complex queries. I'm using ToSql() extension method also when optimizing slow queries to find out what was actually generated by NHibernate.


2 Answers

Here is an article describing how to get the underlying sql from hql or criteria in Hibernate; I'd imagine porting this to use NHibernate wouldn't be too tricky:

http://narcanti.keyboardsamurais.de/hibernate-criteria-to-sql-translation.html

like image 52
DanP Avatar answered Nov 13 '22 15:11

DanP


With NHibernate 3.2, this seems to work to get the SQL from an HQL query:

private string GetSQL(string hql)
{
    using (var iSession = ...)
    {
        var session = (NHibernate.Engine.ISessionImplementor)iSession;
        var sf = (NHibernate.Engine.ISessionFactoryImplementor)iSession.SessionFactory;

        var sql = new NHibernate.Engine.Query.HQLStringQueryPlan(hql, true, session.EnabledFilters, sf);

        return string.Join(";", sql.SqlStrings);
    }
}
like image 41
David McClelland Avatar answered Nov 13 '22 16:11

David McClelland