77 votes

Comment obtenir du SQL à partir de l'API Hibernate Criteria (* pas * pour la journalisation)

Existe-t-il un moyen simple d'obtenir le sql (à générer) à partir d'un critère Hibernate?

Idéalement, j'aurais quelque chose comme:

 Criteria criteria = session.createCriteria(Operator.class);

... build up the criteria ...
... and then do something like ...

String sql = criteria.toSql()

(But this of course does not exist)
 

L'idée serait alors d'utiliser le sql dans le cadre d'une énorme requête 'MINUS' (il me faut trouver les différences entre 2 schémas identiques - de structure identique, pas de données - et le paramètre MINUS n'est pas pris en charge par Hibernate)

(BTW je sais que je peux vérifier le SQL à partir des fichiers journaux)

47voto

ramdane.i Points 274

Voici "un autre" moyen d'obtenir le code SQL:

 CriteriaImpl criteriaImpl = (CriteriaImpl)criteria;
SessionImplementor session = criteriaImpl.getSession();
SessionFactoryImplementor factory = session.getFactory();
CriteriaQueryTranslator translator=new CriteriaQueryTranslator(factory,criteriaImpl,criteriaImpl.getEntityOrClassName(),CriteriaQueryTranslator.ROOT_SQL_ALIAS);
String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() );

CriteriaJoinWalker walker = new CriteriaJoinWalker((OuterJoinLoadable)factory.getEntityPersister(implementors[0]), 
                        translator,
                        factory, 
                        criteriaImpl, 
                        criteriaImpl.getEntityOrClassName(), 
                        session.getLoadQueryInfluencers()   );

String sql=walker.getSQLString();
 

41voto

Brian Deterling Points 7778

J'ai utilisé quelque chose comme ceci en utilisant Spring AOP afin de pouvoir récupérer le SQL, les paramètres, les erreurs et le temps d'exécution de toute requête exécutée dans l'application, qu'il s'agisse de HQL, de critères ou de SQL natif.

Ceci est évidemment fragile, peu sûr, sujet à rupture avec les changements dans Hibernate, etc., mais cela montre qu’il est possible d’obtenir le code SQL:

 CriteriaImpl c = (CriteriaImpl)query;
SessionImpl s = (SessionImpl)c.getSession();
SessionFactoryImplementor factory = (SessionFactoryImplementor)s.getSessionFactory();
String[] implementors = factory.getImplementors( c.getEntityOrClassName() );
CriteriaLoader loader = new CriteriaLoader((OuterJoinLoadable)factory.getEntityPersister(implementors[0]),
    factory, c, implementors[0], s.getEnabledFilters());
Field f = OuterJoinLoader.class.getDeclaredField("sql");
f.setAccessible(true);
String sql = (String)f.get(loader);
 

Enveloppez le tout dans un essai / attraper et utiliser à vos propres risques.

11voto

LiamV Points 541

Pour ceux qui utilisent NHibernate, il s’agit d’un code de port [ram]

 public static string GenerateSQL(ICriteria criteria)
    {
        NHibernate.Impl.CriteriaImpl criteriaImpl = (NHibernate.Impl.CriteriaImpl)criteria;
        NHibernate.Engine.ISessionImplementor session = criteriaImpl.Session;
        NHibernate.Engine.ISessionFactoryImplementor factory = session.Factory;

        NHibernate.Loader.Criteria.CriteriaQueryTranslator translator = 
            new NHibernate.Loader.Criteria.CriteriaQueryTranslator(
                factory, 
                criteriaImpl, 
                criteriaImpl.EntityOrClassName, 
                NHibernate.Loader.Criteria.CriteriaQueryTranslator.RootSqlAlias);

        String[] implementors = factory.GetImplementors(criteriaImpl.EntityOrClassName);

        NHibernate.Loader.Criteria.CriteriaJoinWalker walker = new NHibernate.Loader.Criteria.CriteriaJoinWalker(
            (NHibernate.Persister.Entity.IOuterJoinLoadable)factory.GetEntityPersister(implementors[0]),
                                translator,
                                factory,
                                criteriaImpl,
                                criteriaImpl.EntityOrClassName,
                                session.EnabledFilters);

        return walker.SqlString.ToString();
    }
 

7voto

Michael Points 982

Si vous utilisez Hibernate 3.6, vous pouvez utiliser le code de la réponse acceptée (fournie par Brian Deterling) avec une légère modification:

   CriteriaImpl c = (CriteriaImpl) criteria;
  SessionImpl s = (SessionImpl) c.getSession();
  SessionFactoryImplementor factory = (SessionFactoryImplementor) s.getSessionFactory();
  String[] implementors = factory.getImplementors(c.getEntityOrClassName());
  LoadQueryInfluencers lqis = new LoadQueryInfluencers();
  CriteriaLoader loader = new CriteriaLoader((OuterJoinLoadable) factory.getEntityPersister(implementors[0]), factory, c, implementors[0], lqis);
  Field f = OuterJoinLoader.class.getDeclaredField("sql");
  f.setAccessible(true);
  String sql = (String) f.get(loader);
 

4voto

Triqui Points 401

J'aime ceci si vous voulez obtenir seulement quelques parties de la requête:

 new CriteriaQueryTranslator(factory, executableCriteria, executableCriteria.getEntityOrClassName(), CriteriaQueryTranslator.ROOT_SQL_ALIAS).getWhereCondition();
 

Par exemple, quelque chose comme ceci:

 String where = new CriteriaQueryTranslator(factory, executableCriteria, executableCriteria.getEntityOrClassName(), CriteriaQueryTranslator.ROOT_SQL_ALIAS).getWhereCondition();
String sql = "update my_table this_ set this_.status = 0 where " + where;
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X