现在做的一个项目,应用的是NHibernate,所有的查询基本上是通过hql语句来写的,现在需要将生成的查询结果导出,这就遇到个问题,通过hql语句查询出来的结果返回的是IList,我没找到可以增加列名的方法。
以前调试hql的时候都是在sql server的事件探查器里查看它翻译后的sql,于是想它有没有直接将hql翻译成sql的方法呢,于是一路寻找,可惜没找到,但也发现了一些有用的东西,于是对原有的NHibernate类库做了一些破坏其封装性的修改,使我们似乎可以从外部快速获取hql翻译后的sql,我的修改过程如下:
1
.NHibernate.Hql.
QueryTranslator
类中增加方法如下:
public
string GetSqlString()
{
return sqlString.ToString();
}
由此获取QueryTranslator中对应的sql语句
2
.NHibernate.Impl.
SessionImpl
类中增加方法如下:
public
QueryTranslator[] GetSqlQuery(string hql)
{
return factory.GetQuery(hql, false);
}
由此获取QueryTranslator
3
.NHibernate.Impl.
SessionFactoryImpl
类增加如下方法:
public
SessionImpl OpenSessionObject()
{
long timestamp = Timestamper.Next();
return new SessionImpl(null,this, true, timestamp, interceptor);
}
由此获取Session实体对象
4
.NHibernate.Cfg.
Configuration
类增加如下方法
public
SessionImpl OpenSessionObject()
{
SecondPassCompile();
Validate();
Environment.VerifyProperties(properties);
Settings settings = BuildSettings();
MappingSchemaCollection = null;
CfgSchemaCollection = null;
SessionFactoryImpl sfi = new SessionFactoryImpl(this, mapping, settings);
return sfi.OpenSessionObject();
}
由此获取Session实体对象(因为SessionFactoryImpl为内部方法)
5
.
在外部则可通过如下方法访问翻译后的sql了:
public
string
GetSql(
string
hql)
...
{
Configuration cfg = new Configuration();
cfg.AddAssembly("SafeManage.PersistentObject");
SessionImpl session = (SessionImpl)cfg.OpenSessionObject();
QueryTranslator[] translators = session.GetSqlQuery(hql);
string sourceSql = translators[0].GetSqlString();
return sourceSql ;
}
其实在每个QueryTranslator对象里都有一个SqlString对象存放这翻译后的sql,上面做的内容就是怎样由外部直接访问到这个sql。
我的推敲过程是这样的:
QueryTranslator对hql进行翻译,所以增加一方法直接返回翻译后的sql。
SessionImpl可以返回QueryTranslator,所以增加一方法,直接将QueryTranslator返回。
SessionFactoryImpl可以访问会话,所以增加一方法,直接返回会话对象
Configuration类中可以访问会话工厂,所以增加一方法直接返回SessionFactoryImpl中的SessionImpl对象。
这样的修改破坏了原有类库的封装意图,不太美妙, 由于我也是才开始应用NHibernate,对它还不太熟悉,在获取翻译后的hql的推敲过程中也是迷迷糊糊,希望有人能给出更好的思路。