是否有一种从Hibernate Criteria获取(待生成)sql的简单方法?
理想情况下,我会有类似的东西:
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)
这个想法是使用sql作为巨大的'MINUS'查询的一部分(我需要找到两个相同模式之间的差异 - 结构相同,而不是数据 - 而Hibernate不支持MINUS)
(顺便说一句,我知道我可以从日志文件中检查SQL)
这是获取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();
我使用Spring AOP做了类似的事情,所以我可以获取应用程序中运行的任何查询的sql,参数,错误和执行时间,无论是HQL,Criteria还是本机SQL.
这显然是脆弱的,不安全的,可以打破Hibernate等的变化,但它说明了有可能得到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);
将所有东西包裹在try/catch中并使用,风险自负.
对于那些使用NHibernate的人来说,这是[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(); }
如果您使用的是Hibernate 3.6,您可以使用接受的答案中的代码(由Brian Deterling提供)稍作修改:
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);