query print ejemplo java sql hibernate criteria

java - print - Cómo obtener SQL de la API de criterios de Hibernate(* no*para el registro)



hibernate criteria join (8)

¿Hay alguna manera fácil de obtener el sql (generado) a partir de un criterio de Hibernate?

Idealmente, tendría algo como:

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)

La idea entonces sería usar el sql como parte de una enorme consulta ''MINUS'' (necesito encontrar las diferencias entre 2 esquemas idénticos - idénticos en estructura, no en datos - y MINUS no es compatible con Hibernate)

(Por cierto, sé que puedo verificar el SQL de los archivos de registro)


Aquí hay "otra" forma de obtener el 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();


Aquí hay un método que usé y funcionó para mí

public static String toSql(Session session, Criteria criteria){ String sql=""; Object[] parameters = null; try{ CriteriaImpl c = (CriteriaImpl) criteria; 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); sql = (String)f.get(loader); Field fp = CriteriaLoader.class.getDeclaredField("traslator"); fp.setAccessible(true); CriteriaQueryTranslator translator = (CriteriaQueryTranslator) fp.get(loader); parameters = translator.getQueryParameters().getPositionalParameterValues(); } catch(Exception e){ throw new RuntimeException(e); } if (sql !=null){ int fromPosition = sql.indexOf(" from "); sql = "SELECT * "+ sql.substring(fromPosition); if (parameters!=null && parameters.length>0){ for (Object val : parameters) { String value="%"; if(val instanceof Boolean){ value = ((Boolean)val)?"1":"0"; }else if (val instanceof String){ value = "''"+val+"''"; } sql = sql.replaceFirst("//?", value); } } } return sql.replaceAll("left outer join", "/nleft outer join").replace(" and ", "/nand ").replace(" on ", "/non "); }


Esta respuesta se basa en la respuesta del usuario3715338 (con un pequeño error ortográfico corregido) y se mezcla con la respuesta de Michael para Hibernate 3.6, según la respuesta aceptada de Brian Deterling. Luego lo extendí (para PostgreSQL) con un par de tipos más que reemplazan las preguntas:

public static String toSql(Criteria criteria) { String sql = ""; Object[] parameters = null; try { CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; SessionImpl sessionImpl = (SessionImpl) criteriaImpl.getSession(); SessionFactoryImplementor factory = sessionImpl.getSessionFactory(); String[] implementors = factory.getImplementors(criteriaImpl.getEntityOrClassName()); OuterJoinLoadable persister = (OuterJoinLoadable) factory.getEntityPersister(implementors[0]); LoadQueryInfluencers loadQueryInfluencers = new LoadQueryInfluencers(); CriteriaLoader loader = new CriteriaLoader(persister, factory, criteriaImpl, implementors[0].toString(), loadQueryInfluencers); Field f = OuterJoinLoader.class.getDeclaredField("sql"); f.setAccessible(true); sql = (String) f.get(loader); Field fp = CriteriaLoader.class.getDeclaredField("translator"); fp.setAccessible(true); CriteriaQueryTranslator translator = (CriteriaQueryTranslator) fp.get(loader); parameters = translator.getQueryParameters().getPositionalParameterValues(); } catch (Exception e) { throw new RuntimeException(e); } if (sql != null) { int fromPosition = sql.indexOf(" from "); sql = "/nSELECT * " + sql.substring(fromPosition); if (parameters != null && parameters.length > 0) { for (Object val : parameters) { String value = "%"; if (val instanceof Boolean) { value = ((Boolean) val) ? "1" : "0"; } else if (val instanceof String) { value = "''" + val + "''"; } else if (val instanceof Number) { value = val.toString(); } else if (val instanceof Class) { value = "''" + ((Class) val).getCanonicalName() + "''"; } else if (val instanceof Date) { SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS"); value = "''" + sdf.format((Date) val) + "''"; } else if (val instanceof Enum) { value = "" + ((Enum) val).ordinal(); } else { value = val.toString(); } sql = sql.replaceFirst("//?", value); } } } return sql.replaceAll("left outer join", "/nleft outer join").replaceAll( " and ", "/nand ").replaceAll(" on ", "/non ").replaceAll("<>", "!=").replaceAll("<", " < ").replaceAll(">", " > "); }


He hecho algo como esto usando Spring AOP para poder tomar SQL, los parámetros, los errores y el tiempo de ejecución para cualquier consulta ejecutada en la aplicación, ya sea HQL, Criteria o SQL nativo.

Esto es obviamente frágil, inseguro, sujeto a romper con los cambios en Hibernate, etc., pero ilustra que es posible obtener el 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);

Envuelva todo en una prueba / captura y use bajo su propio riesgo.


Me gusta esto si quiere obtener solo algunas partes de la consulta:

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

Por ejemplo algo como esto:

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;


Para aquellos que usan NHibernate, este es un código de puerto de [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(); }


Para cualquiera que desee hacer esto en una sola línea (por ejemplo, en la ventana Mostrar / Inmediato, una expresión de reloj o similar en una sesión de depuración), lo siguiente lo hará e "imprima bastante" el SQL:

new org.hibernate.jdbc.util.BasicFormatterImpl().format((new org.hibernate.loader.criteria.CriteriaJoinWalker((org.hibernate.persister.entity.OuterJoinLoadable)((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory().getEntityPersister(((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory().getImplementors(((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName())[0]),new org.hibernate.loader.criteria.CriteriaQueryTranslator(((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory(),((org.hibernate.impl.CriteriaImpl)crit),((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName(),org.hibernate.loader.criteria.CriteriaQueryTranslator.ROOT_SQL_ALIAS),((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory(),(org.hibernate.impl.CriteriaImpl)crit,((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName(),((org.hibernate.impl.CriteriaImpl)crit).getSession().getEnabledFilters())).getSQLString());

... o aquí hay una versión más fácil de leer:

new org.hibernate.jdbc.util.BasicFormatterImpl().format( (new org.hibernate.loader.criteria.CriteriaJoinWalker( (org.hibernate.persister.entity.OuterJoinLoadable) ((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory().getEntityPersister( ((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory().getImplementors( ((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName())[0]), new org.hibernate.loader.criteria.CriteriaQueryTranslator( ((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory(), ((org.hibernate.impl.CriteriaImpl)crit), ((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName(), org.hibernate.loader.criteria.CriteriaQueryTranslator.ROOT_SQL_ALIAS), ((org.hibernate.impl.CriteriaImpl)crit).getSession().getFactory(), (org.hibernate.impl.CriteriaImpl)crit, ((org.hibernate.impl.CriteriaImpl)crit).getEntityOrClassName(), ((org.hibernate.impl.CriteriaImpl)crit).getSession().getEnabledFilters() ) ).getSQLString() );

Notas:

  1. La respuesta se basa en la solución publicada por ramdane.i .
  2. Asume que el objeto Criteria se llama crit . Si recibe un nombre diferente, haga una búsqueda y reemplace .
  3. Asume que la versión de Hibernate es posterior a 3.3.2.GA pero anterior a 4.0 para utilizar BasicFormatterImpl para "imprimir bastante" el HQL. Si usa una versión diferente, vea esta respuesta para saber cómo modificarla. O tal vez simplemente elimine por completo la bonita impresión, ya que es simplemente un "buen regalo" .
  4. Está utilizando getEnabledFilters lugar de getLoadQueryInfluencers() para compatibilidad con versiones anteriores ya que este último se introdujo en una versión posterior de Hibernate (3.5 ???)
  5. No genera los valores de parámetro reales utilizados si la consulta está parametrizada.

Si está utilizando Hibernate 3.6, puede usar el código en la respuesta aceptada (proporcionada por Brian Deterling) con una ligera modificación:

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);